Objetivo

El objetivo de este informe es estimar la regla de Taylor utilizando métodos tradicionales (OLS) y modelos bayesianos. Para la especificación de los priors y ciertos parámetros de referencia se utilizan valores documentados en distintos trabajos académicos, en particular un artículo del BIS (Bank for International Settlements), que presenta información acerca de política monetaria.

Configuración Inicial

Importación de librerías

Para el desarrollo del análisis se requiere la carga de librerías específicas para el manejo y transformación de datos, el trabajo con fechas, la estimación de modelos bayesianos y la generación de gráficos.

library(lubridate)
library(dplyr)
library(bayesreg)   
library(MCMCpack)
library(tidyr)
library(cmdstanr)
library(brms)
library(broom)
library(tidybayes)
library(ggplot2)
library(ggdist)
library(bayesplot)
library(posterior)
library(plotly)
library(gridExtra)
library(scales)
library(rlang)
library(purrr)

Importación del dataset

Se define el directorio de trabajo y luego se importa el archivo que contiene las series macroeconómicas utilizadas en el análisis.

setwd("G:/My Drive/TP EEA")

dataset <- read.csv("G:/My Drive/TP EEA/2025-09-QD.csv")

head(dataset)
gdppot <- read.csv("GDPPOT.csv")

head(gdppot)

Transformación de datos

Se realizan correcciones necesarias antes del análisis y se mergean los datasets.

dataset <- dataset[-c(1, 2), ]  # Se eliminan filas iniciales
dataset$sasdate <- as.Date(dataset$sasdate, format = "%m/%d/%Y")  # Conversión a fechas
dataset$quarter_label <- paste0(year(dataset$sasdate), "Q", quarter(dataset$sasdate)) # Etiqueta trimestral
dataset <- dataset[order(dataset$sasdate), ]   # Orden temporal
dataset$time_index <- seq_len(nrow(dataset))    # Índice de tiempo
dataset <- dataset %>% relocate(quarter_label, time_index, .after = 1)  # Reorganización de columnas
gdppot$observation_date <- gsub("-", "/", gdppot$observation_date)
gdppot$observation_date <- as.Date(gdppot$observation_date, format = "%m/%d/%Y") # Conversión a fechas

dataset <- dataset %>%
  left_join(
    gdppot,
    by = c("sasdate" = "observation_date")
  )

 #Selecciono variables
df <- dataset %>%
  dplyr::select(
    sasdate,
    quarter_label,
    time_index,
    PCECTPI,
    GDPC1,
    GDPPOT,
    FEDFUNDS,
    TCU, #variable de control
    USGOVT, #variable de control
    UNRATE, #variable de control
    DGDSRG3Q086SBEA, #variable de control
    GS10TB3Mx, #variable de control
    CPF3MTB3Mx, #variable de control
    BOGMBASEREALx #variable de control
  )

# Filtrar el rango de fechas para las series
df_filtered <- df %>%
  filter(sasdate > as.Date("1980-01-01") & sasdate < as.Date("2007-01-01"))

head(df_filtered)

Análisis Exploratorio

La Regla de Taylor es un modelo ampliamente utilizado en macroeconomía para describir cómo debería reaccionar la política monetaria ante desvíos de la inflación respecto de su meta y ante fluctuaciones del producto respecto de su nivel potencial. Para estimarla empíricamente, se requiere construir una serie de variables macroeconómicas clave: el output gap, la inflación trimestral y la brecha de inflación (inflation gap).

Selección de variables relevantes

En primer lugar, se construye un subconjunto del dataset original conservando únicamente las series necesarias para el análisis. Las principales variables macroeconómicas utilizadas son:

  • PCECTPI — Índice de Precios de los Gastos en Consumo Personal: indicador de inflación utilizado por la Reserva Federal de Estados Unidos. Mide la evolución del nivel de precios de bienes y servicios consumidos por los hogares.
  • GDPC1 — Producto Bruto Interno Real: mide el nivel de actividad económica ajustado por inflación y refleja la cantidad real de bienes y servicios producidos en la economía.
  • GDPPOT — Producto Potencial: representa el nivel de producción que la economía podría sostener de manera sostenible, sin generar presiones inflacionarias persistentes.
  • FEDFUNDS — Tasa de Fondos Federales: tasa de interés de referencia fijada por la Reserva Federal.
# 1) Producto (GDPC1 y GDPPOT) juntos
df_productos <- df_filtered %>%
  dplyr::select(sasdate, GDPC1, GDPPOT) %>%
  pivot_longer(cols = c(GDPC1, GDPPOT), names_to = "variable", values_to = "value")

p1 <- ggplot(df_productos, aes(x = sasdate, y = value, color = variable)) +
  geom_line(size = 1) +
  labs(title = "Producto Interno Bruto Real y Producto Potencial",
       x = "Fecha",
       y = "Valor") +
  theme_minimal() +
  theme(legend.title = element_blank())

# 2) Tasa de interés FEDFUNDS sola
df_tasa <- df_filtered %>%
  dplyr::select(sasdate, FEDFUNDS)

p2 <- ggplot(df_tasa, aes(x = sasdate, y = FEDFUNDS)) +
  geom_line(color = "steelblue", size = 1) +
  labs(title = "Tasa de Fondos Federales (FEDFUNDS)",
       x = "Fecha",
       y = "Tasa (%)") +
  theme_minimal()

# Mostrar los gráficos uno debajo del otro
grid.arrange(p1, p2, ncol = 1)

Output Gap

El output gap mide el desvío porcentual del Producto Interno Bruto real (GDPC1) respecto de su nivel potencial (GDPPOT). La siguiente transformación calcula esta brecha en puntos porcentuales:

df <- df %>%
  mutate(
    y_gap = 100 * (GDPC1 - GDPPOT) / GDPPOT)


# Seleccionamos la variable y pasamos a formato largo
df_long <- df %>%
  dplyr::select(sasdate,y_gap) %>%
  pivot_longer(cols = -sasdate, names_to = "variable", values_to = "value")

df_long <- df_long %>%
  filter(sasdate > as.Date("1980-01-01") & sasdate < as.Date("2007-01-01") )

# Gráfico histórico
ggplot(df_long, aes(x = sasdate, y = value, color = variable)) +
  geom_line(size = 1) +
  facet_wrap(~variable, scales = "free_y", ncol = 2) +
  labs(title = "Series historicas del y_gap",
       x = "Fecha",
       y = "Valor") +
  theme_minimal()

Inflation Gap

La brecha de inflación mide el desvío entre la inflación observada y la meta implícita de la Reserva Federal. Para este trabajo se utiliza un objetivo anual del 2%, que en frecuencia trimestral equivale aproximadamente a 0,5%. La variable pi_gap se define entonces como la diferencia entre la inflación trimestral estimada a partir del índice PCE y esta meta.

# Inflacion Trimestral objetivo
pi_star_q <- 0.5

# Extraemos del indice de precios la inflacion trimestral con la aproximacion log-diff
df <- df %>%
  arrange(sasdate) %>%
  mutate(
    infl_q = 100 * (log(PCECTPI) - dplyr::lag(log(PCECTPI), 1)), # inflación trimestral en % (aprox log-diff)
    pi_gap = infl_q - pi_star_q
  ) %>%
  drop_na(pi_gap)

# Seleccionamos la variable y pasamos a formato largo
df_long <- df %>%
  dplyr::select(sasdate,pi_gap) %>%
  pivot_longer(cols = -sasdate, names_to = "variable", values_to = "value")

df_long <- df_long %>%
  filter(sasdate > as.Date("1980-01-01") & sasdate < as.Date("2007-01-01") )

# Gráfico histórico
ggplot(df_long, aes(x = sasdate, y = value, color = variable)) +
  geom_line(size = 1) +
  facet_wrap(~variable, scales = "free_y", ncol = 2) +
  labs(title = "Series historicas del desvio de la inflacion respecto a la objetiva",
       x = "Fecha",
       y = "Valor") +
  theme_minimal()

Inercia de la tasa de interés

Para capturar el comportamiento gradual de la política monetaria, se incorpora la tasa de fondos federales rezagada un período (i_lag1). Esta variable refleja la inercia típica con la que la Reserva Federal ajusta la tasa de interés, dado que los cambios suelen realizarse de manera progresiva y no abrupta de un trimestre a otro.

# Contruimos las variables lags de interes y cambio en la tasa de interes
df <- df %>%
  arrange(sasdate) %>%
  mutate(
    i_lag1   = dplyr::lag(FEDFUNDS, 1), # tasa rezagada 1
    delta_i  = FEDFUNDS - i_lag1 # cambio en la tasa
  ) %>%
  drop_na(i_lag1, delta_i)

df_long <- df %>%
  dplyr::select(sasdate, delta_i, FEDFUNDS) %>%
  pivot_longer(cols = -sasdate, names_to = "variable", values_to = "value") %>%
  filter(sasdate > as.Date("1980-01-01") & sasdate < as.Date("2007-01-01")) %>%
  mutate(
    variable = recode(variable,
                      FEDFUNDS = "FEDFUNDS",
                      delta_i  = "Delta_i"),
    variable = factor(variable, levels = c("FEDFUNDS", "Delta_i"))
  )

ggplot(df_long, aes(x = sasdate, y = value, color = variable)) +
  geom_line(size = 1) +
  facet_wrap(~variable, scales = "free_y", nrow = 2) +
  labs(
    title = "Series históricas de la tasa de interés y su cambio respecto al trimestre anterior",
    x = "Fecha",
    y = "Valor",
    color = "Variables"
  ) +
  scale_color_manual(
    values = c("FEDFUNDS" = "#1F77B4", "Delta_i" = "#FF7F0E"),
    labels = c("FEDFUNDS" = "FEDFUNDS", "Delta_i" = "Delta_i")
  ) +
  scale_y_continuous(labels = scales::label_number(accuracy = 0.1)) +
  theme_minimal()

Análisis Estadisticos de las variables

En primer lugar, analizaremos las variables a través de sus medidas de tendencia para el periodo en cuestión.

df_desc <- df %>% filter(sasdate > as.Date("1980-01-01") & sasdate < as.Date("2007-01-01") )

df_desc <- df_desc %>% dplyr::select(GDPC1, GDPPOT, FEDFUNDS, y_gap, infl_q, pi_gap, delta_i)

summary_stats <- df_desc %>%
  summarise(
    across(
      everything(),
      list(
        min  = ~min(. , na.rm = TRUE),
        max  = ~max(. , na.rm = TRUE),
        mean = ~mean(. , na.rm = TRUE),
        sd   = ~sd(. , na.rm = TRUE)
      ),
      .names = "{.col}_{.fn}"
    )
  ) %>%
  pivot_longer(
    everything(),
    names_to = c("variable", "stat"),
    names_pattern = "(.*)_(.*)"
  ) %>%
  pivot_wider(names_from = stat, values_from = value) %>%
  mutate(across(where(is.numeric), ~round(. , 2)))

summary_stats

En segundo lugar, analizaremos la evolución de las variables desde el enfoque histórico de las series de tiempo. Con el fin de representarlas de manera conjunta en un mismo gráfico, recurrimos al proceso de estandarización. Este procedimiento transforma cada observación en un z‑score, es decir, en la cantidad de desviaciones estándar que dicho valor se encuentra por encima o por debajo de la media de la variable. De esta forma, las tres series quedan expresadas en una escala común, lo que facilita la comparación de sus dinámicas a lo largo del tiempo.

# Seleccionamos las variables y pasamos a formato largo

df_norm <- df %>%
  dplyr::select(sasdate, FEDFUNDS, pi_gap, y_gap) %>%
  mutate(
    FEDFUNDS_z = scale(FEDFUNDS),
    pi_gap_z   = scale(pi_gap),
    y_gap_z    = scale(y_gap)
  ) %>%
  dplyr::select(sasdate, FEDFUNDS_z, pi_gap_z, y_gap_z) %>%
  pivot_longer(
    cols = -sasdate,
    names_to = "variable",
    values_to = "value"
  )  %>% 
    filter(sasdate > as.Date("1980-01-01") & sasdate < as.Date("2007-01-01") )

p <- ggplot(df_norm, aes(
    x = sasdate,
    y = value,
    color = variable,
    group = variable,
    text = paste0(
      "Fecha: ", format(sasdate, "%Y-%m"), "<br>",
      "Variable: ", dplyr::recode(variable,
                                  FEDFUNDS_z = "Tasa Fed",
                                  pi_gap_z   = "Inflation gap",
                                  y_gap_z    = "Output gap"), "<br>",
      "Valor: ", sprintf("%.2f", value)
    )
  )) +
  geom_line(size = 1.2) +
  labs(
    title = "Evolución comparada: tasa de la Fed y brechas (normalizadas)",
    x = "Fecha",
    y = "Valores normalizados (z-score)",
    color = NULL
  ) +
  scale_color_manual(
    values = c(
      FEDFUNDS_z = "#1F77B4",
      pi_gap_z   = "#AEC7E8",
      y_gap_z    = "#98DF8A"
    ),
    labels = c("Tasa Fed", "Inflation gap", "Output gap")
  ) +
  theme_minimal(base_size = 14) +
  theme(
    legend.position = "bottom",
    legend.text = element_text(size = 9),
    plot.title = element_text(face = "bold", size = 12, hjust = 0.5),
    axis.title = element_text(face = "bold"),
    axis.text = element_text(color = "gray30")
  )

ggplotly(p, tooltip = "text") %>%
  layout(
    legend = list(
      orientation = "h",
      x = 0.2,
      y = 0.1
    )
  )

Regresiones

OLS

Se determina una ventana temporal y se procede con la regresión tradicional.

df_reg_sub <- df %>%
  filter(sasdate > as.Date("1980-01-01") & sasdate < as.Date("2007-01-01") )
taylor_ols <- lm(
  FEDFUNDS ~ i_lag1 + pi_gap + y_gap,
  data = df_reg_sub
)

summary(taylor_ols)
## 
## Call:
## lm(formula = FEDFUNDS ~ i_lag1 + pi_gap + y_gap, data = df_reg_sub)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -3.0362 -0.2918  0.0126  0.2851  5.1733 
## 
## Coefficients:
##             Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  0.50005    0.19319   2.588 0.011024 *  
## i_lag1       0.88716    0.03250  27.296  < 2e-16 ***
## pi_gap       0.89037    0.22647   3.932 0.000152 ***
## y_gap        0.16600    0.04975   3.337 0.001176 ** 
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.9141 on 104 degrees of freedom
## Multiple R-squared:  0.9401, Adjusted R-squared:  0.9384 
## F-statistic: 544.4 on 3 and 104 DF,  p-value: < 2.2e-16

La estimación OLS de la Regla de Taylor arroja un coeficiente de inercia elevado para la tasa de interés (i_lag1 ≈ 0,89), lo que indica que la Reserva Federal ajusta la política monetaria de manera gradual. Tanto la brecha de inflación (pi_gap ≈ 0,89) como el output gap (y_gap ≈ 0,17) presentan signos positivos y son estadísticamente significativos, en línea con la idea de que la tasa de fondos federales aumenta cuando la inflación se ubica por encima de la meta y cuando la actividad se sitúa por encima de su nivel potencial. El modelo exhibe un muy buen ajuste (R² ≈ 0,94), por lo que la especificación estimada captura razonablemente bien el comportamiento histórico de la política monetaria en el período considerado.

Regresión Bayesiana #1 - Priors Débiles

Además de la estimación mediante Mínimos Cuadrados Ordinarios, se implementó una versión bayesiana de la Regla de Taylor. Este enfoque permite combinar la información presente en los datos con conocimiento previo sobre el comportamiento típico de la política monetaria. Para esta primera especificación se utilizaron priors informativas basadas en estimaciones reportadas en estudios del BIS, que reflejan valores típicos para la inercia monetaria y las respuestas a inflación y actividad económica.

priors_v1 <- c(
  prior(normal(0,    5), class = "Intercept"),
  prior(normal(0.74, 2), class = "b", coef = "i_lag1"),
  prior(normal(2.11, 2), class = "b", coef = "pi_gap"),
  prior(normal(0.26, 2), class = "b", coef = "y_gap"),
  
# Prior débil para sigma (desvío estándar residual)
  prior(student_t(3, 0, 10), class = "sigma")
)

set.seed(42)

taylor_bayes_v1_brms <- brm(
  FEDFUNDS ~ i_lag1 + pi_gap + y_gap,
  data   = df_reg_sub,
  family = gaussian(),
  prior  = priors_v1,
  chains = 4,
  iter   = 15000,   # total draws por cadena
  warmup = 5000,    # burn-in
  cores  = 4,
  seed   = 42,
  sample_prior = "yes"
)
summary(taylor_bayes_v1_brms)
##  Family: gaussian 
##   Links: mu = identity 
## Formula: FEDFUNDS ~ i_lag1 + pi_gap + y_gap 
##    Data: df_reg_sub (Number of observations: 108) 
##   Draws: 4 chains, each with iter = 15000; warmup = 5000; thin = 1;
##          total post-warmup draws = 40000
## 
## Regression Coefficients:
##           Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## Intercept     0.50      0.20     0.11     0.89 1.00    39166    32860
## i_lag1        0.89      0.03     0.82     0.95 1.00    33831    29398
## pi_gap        0.90      0.23     0.46     1.35 1.00    35069    31239
## y_gap         0.17      0.05     0.07     0.26 1.00    43577    28867
## 
## Further Distributional Parameters:
##       Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## sigma     0.93      0.07     0.81     1.06 1.00    45642    29975
## 
## Draws were sampled using sampling(NUTS). For each parameter, Bulk_ESS
## and Tail_ESS are effective sample size measures, and Rhat is the potential
## scale reduction factor on split chains (at convergence, Rhat = 1).

Los resultados bayesianos con priors débiles son muy similares a los de OLS: los coeficientes de inercia, inflación y output gap mantienen magnitudes casi idénticas y continúan siendo claramente significativos. Los intervalos al 95% reflejan la misma información que los intervalos de confianza clásicos, indicando que las priors no alteran sustancialmente la estimación. En síntesis, el modelo bayesiano reproduce de manera consistente la estructura obtenida por OLS.

Regresión Bayesiana #2 - Priors Fuertes

En esta segunda especificación se mantiene la misma estructura del modelo, pero se reemplazan las priors débiles por priors mucho más concentradas, basadas en estimaciones del BIS. Esto permite evaluar cuánto influyen las creencias previas en los coeficientes de la Regla de Taylor, forzando al modelo a comenzar desde valores muy específicos para la inercia monetaria, la respuesta a la inflación y la respuesta al ciclo.

priors_v2 <- c(
  prior(normal(0,    5.0), class = "Intercept"),
  prior(normal(0.74, 0.10), class = "b", coef = "i_lag1"),
  prior(normal(2.11, 0.10), class = "b", coef = "pi_gap"),
  prior(normal(0.26, 0.05), class = "b", coef = "y_gap"),
  
# Prior débil para sigma (análogo a inv-gamma muy plana en sigma^2)
  prior(student_t(3, 0, 10), class = "sigma")
)

set.seed(42)

taylor_bayes_v2_brms <- brm(
  FEDFUNDS ~ i_lag1 + pi_gap + y_gap,
  data   = df_reg_sub,
  family = gaussian(),
  prior  = priors_v2,
  
  chains = 4,
  iter   = 15000,
  warmup = 5000,
  cores  = 4,
  seed   = 42,
  sample_prior = "yes"
)
summary(taylor_bayes_v2_brms)
##  Family: gaussian 
##   Links: mu = identity 
## Formula: FEDFUNDS ~ i_lag1 + pi_gap + y_gap 
##    Data: df_reg_sub (Number of observations: 108) 
##   Draws: 4 chains, each with iter = 15000; warmup = 5000; thin = 1;
##          total post-warmup draws = 40000
## 
## Regression Coefficients:
##           Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## Intercept     0.85      0.19     0.47     1.23 1.00    45059    32471
## i_lag1        0.79      0.03     0.74     0.85 1.00    40639    31120
## pi_gap        1.95      0.09     1.76     2.13 1.00    41106    32861
## y_gap         0.22      0.04     0.15     0.30 1.00    45001    32105
## 
## Further Distributional Parameters:
##       Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## sigma     1.01      0.07     0.88     1.17 1.00    42290    31769
## 
## Draws were sampled using sampling(NUTS). For each parameter, Bulk_ESS
## and Tail_ESS are effective sample size measures, and Rhat is the potential
## scale reduction factor on split chains (at convergence, Rhat = 1).

Los resultados con priors fuertes muestran coeficientes claramente influenciados por la información previa: la respuesta a la inflación aumenta de manera marcada (≈ 1.95), mientras que la inercia monetaria se reduce (≈ 0.79), moviéndose ambos en dirección a los valores fijados en las priors. El output gap también presenta un coeficiente mayor (≈ 0.22). Todos los parámetros resultan estadísticamente significativos reflejando la mayor precisión impuesta por las priors. En conjunto, esta versión del modelo ilustra cómo priors más concentradas pueden modificar sustancialmente las estimaciones.

Análisis Gráfico

1) Forest plot

El gráfico compara los coeficientes estimados por OLS con las distribuciones posteriores obtenidas bajo los modelos bayesianos con priors débiles y fuertes. Se observa que, mientras la versión con priors débiles reproduce casi exactamente los valores de OLS, las priors fuertes desplazan las distribuciones hacia los valores impuestos por la información previa, especialmente en la respuesta a la inflación. Esto permite visualizar de manera directa cómo el peso de las priors afecta la estimación de cada parámetro.

# i) Coeficientes OLS
ols_tidy <- broom::tidy(taylor_ols, conf.int = TRUE) %>%
  filter(term != "(Intercept)") %>%
  mutate(model = "OLS")

# ii) Coeficientes Bayes: draws de brms
b1_draws <- taylor_bayes_v1_brms %>%
  spread_draws(b_i_lag1, b_pi_gap, b_y_gap) %>%
  dplyr::select(b_i_lag1, b_pi_gap, b_y_gap) %>%
  pivot_longer(cols = everything(),
               names_to = "term",
               values_to = "value") %>%
  mutate(model = "Modelo con priors débiles")

b2_draws <- taylor_bayes_v2_brms %>%
  spread_draws(b_i_lag1, b_pi_gap, b_y_gap) %>%
  dplyr::select(b_i_lag1, b_pi_gap, b_y_gap) %>%
  pivot_longer(cols = everything(),
               names_to = "term",
               values_to = "value") %>%
  mutate(model = "Modelo con priors fuertes")

bayes_draws <- bind_rows(b1_draws, b2_draws) %>%
  mutate(term = recode(term,
                       b_i_lag1 = "i_lag1 (rho)",
                       b_pi_gap = "pi_gap (phi_pi)",
                       b_y_gap  = "y_gap (phi_y)"))

ols_tidy <- ols_tidy %>%
  mutate(term = recode(term,
                       i_lag1 = "i_lag1 (rho)",
                       pi_gap = "pi_gap (phi_pi)",
                       y_gap  = "y_gap (phi_y)"))

# iii) Gráfico combinado
ggplot(bayes_draws, aes(x = value, y = term, fill = model)) +
  stat_halfeye(alpha = 0.7, point_interval = median_qi, .width = 0.95) +
  geom_point(data = ols_tidy, aes(x = estimate, y = term),
             inherit.aes = FALSE, shape = 21, size = 2.2, fill = "white") +
  geom_errorbarh(data = ols_tidy,
                 aes(xmin = conf.low, xmax = conf.high, y = term),
                 inherit.aes = FALSE, height = 0.15) +
  labs(x = "Valor del coeficiente", y = NULL,
       title = "OLS vs Bayes",
       subtitle = "Distribuciones posteriores y IC OLS") +
  theme_minimal()

2) Prior vs Posterior (para #1 y #2)

El gráfico muestra cómo se comparan las distribuciones prior y posterior en ambos modelos. Con priors débiles, los datos modifican fuertemente la distribución posterior. Con priors fuertes, la posterior permanece muy cerca de la prior, indicando que la información previa tiene mucho más peso en la estimación.

pars <- c("b_i_lag1", "b_pi_gap", "b_y_gap")

make_prior_post_long <- function(fit, label){
  prior_df <- prior_draws(fit) %>%
    as_draws_df() %>%
    dplyr::select(all_of(pars)) %>%
    pivot_longer(everything(), names_to = "term", values_to = "value") %>%
    mutate(type = "Prior", model = label)
  
  post_df <- as_draws_df(fit) %>%
    dplyr::select(all_of(pars)) %>%
    pivot_longer(everything(), names_to = "term", values_to = "value") %>%
    mutate(type = "Posterior", model = label)
  
  bind_rows(prior_df, post_df)
}

df_v1 <- make_prior_post_long(taylor_bayes_v1_brms, "Priors débiles")
df_v2 <- make_prior_post_long(taylor_bayes_v2_brms, "Priors fuertes")

df_all <- bind_rows(df_v1, df_v2) %>%
  mutate(
    term = recode(term,
                  b_i_lag1 = "i_lag1 (rho)",
                  b_pi_gap = "pi_gap (phi_pi)",
                  b_y_gap  = "y_gap (phi_y)"),
    term = factor(term, levels = c("i_lag1 (rho)", "pi_gap (phi_pi)", "y_gap (phi_y)"))
  )

ggplot(df_all, aes(x = value, y = term, fill = type)) +
  stat_halfeye(alpha = 0.6, position = "identity",
               point_interval = median_qi, .width = 0.95) +
  facet_wrap(~model) +
  coord_cartesian(xlim = c(-1, 4)) +
  labs(
    title = "Prior vs Posterior por modelo",
    subtitle = "Comparación visual para priors débiles y fuertes",
    x = "Valor del coeficiente", y = NULL
  ) +
  theme_minimal()

3) Comparación Predictiva: Fitted vs actual

El gráfico compara la tasa observada con las predicciones obtenidas por OLS y por los modelos bayesianos con priors débiles y fuertes. En ambos casos, las predicciones bayesianas siguen muy de cerca la trayectoria histórica de la tasa de fondos federales, y las bandas creíbles (50% y 95%) son estrechas, indicando buena precisión del modelo. Las priors fuertes producen intervalos ligeramente más concentrados, reflejando mayor peso de la información previa.

df_plot <- df_reg_sub %>%
  mutate(fit_ols = predict(taylor_ols, newdata = df_reg_sub))

pred_v1 <- df_reg_sub %>%
  add_epred_draws(taylor_bayes_v1_brms, ndraws = 2000)

pred_v2 <- df_reg_sub %>%
  add_epred_draws(taylor_bayes_v2_brms, ndraws = 2000)

summ_pred <- function(pred_df, label){
  pred_df %>%
    group_by(sasdate) %>%
    median_qi(.epred, .width = c(0.5, 0.95)) %>%
    mutate(model = label)
}

p1 <- summ_pred(pred_v1, "Bayes priors débiles")
p2 <- summ_pred(pred_v2, "Bayes priors fuertes")

pred_bands <- bind_rows(p1, p2)

ggplot(df_plot, aes(x = sasdate, y = FEDFUNDS)) +
  geom_line(color = "black") +
  geom_line(aes(y = fit_ols), linetype = "dashed") +
  stat_lineribbon(data = pred_bands,
                  aes(y = .epred, ymin = .lower, ymax = .upper, fill = model),
                  alpha = 0.25) +
  facet_wrap(~model, ncol = 1) +
  labs(title = "Predicción: OLS vs Bayes",
       subtitle = "Bandas creíbles 50% y 95%",
       y = "FEDFUNDS", x = NULL) +
  theme_minimal()

4) Distribucion de reacción a inflación

La figura muestra la distribución posterior del parámetro que mide la respuesta de la tasa de interés a la inflación (ϕπ) bajo ambos conjuntos de priors. Con priors débiles, la distribución es más dispersa y centrada alrededor de valores cercanos a 1, mientras que con priors fuertes se concentra en torno al benchmark de 2.11 propuesto por el BIS (línea punteada). Esto ilustra cómo la información previa influye en la magnitud estimada de la reacción de política monetaria.

b1_phi_pi <- as_draws_df(taylor_bayes_v1_brms)$b_pi_gap
b2_phi_pi <- as_draws_df(taylor_bayes_v2_brms)$b_pi_gap

df_phi <- tibble(
  value = c(b1_phi_pi, b2_phi_pi),
  model = rep(c("Priors débiles","Priors fuertes"),
              c(length(b1_phi_pi), length(b2_phi_pi)))
)

ggplot(df_phi, aes(x = value, fill = model)) +
  geom_density(alpha = 0.5) +
  geom_vline(
    xintercept = 2.11,
    linetype = "dotted",
    linewidth = 1.2,
    color = "black",
    alpha = 0.9
  ) +
  labs(title = "Respuesta a inflación (phi_pi)",
       subtitle = "Línea punteada = benchmark BIS",
       x = expression(phi[pi]), y = "Densidad") +
  theme_minimal()

5) Stacked PPC

Los gráficos PPC permiten evaluar si los modelos bayesianos pueden reproducir la distribución observada de la tasa de interés. Tanto el modelo con priors débiles como el de priors fuertes generan distribuciones simuladas coherentes con los datos reales, lo que indica un ajuste adecuado.

pp_check(taylor_bayes_v1_brms,
         type = "dens_overlay",
         ndraws = 50) +
  ggtitle("PPC - Priors Débiles") +
  labs(x = "FEDFUNDS", y = "Densidad") +
  scale_y_continuous(expand = expansion(mult = c(0, 0.05))) +
  theme_minimal(base_size = 12)

pp_check(taylor_bayes_v2_brms,
         type = "dens_overlay",
         ndraws = 50) +
  ggtitle("PPC - Priors Fuertes") +
  labs(x = "FEDFUNDS", y = "Densidad") +
  scale_y_continuous(expand = expansion(mult = c(0, 0.05))) +
  theme_minimal(base_size = 12)

Bayesian Lasso

En esta sección se extiende la estimación de la Regla de Taylor incorporando un conjunto de variables macroeconómicas adicionales (controles). Para evitar sobreajuste y permitir que el propio modelo determine cuáles de estos controles son realmente relevantes, se utiliza un enfoque bayesiano con un prior tipo LASSO (distribución Laplace), que induce shrinkage sobre todos los coeficientes adicionales. Los coeficientes centrales de la Regla de Taylor —inercia, brecha de inflación y output gap— se mantienen con priors informativos fuertes asegurando que LASSO actúe únicamente sobre los controles. Este enfoque permite evaluar simultáneamente la robustez de la regla y el aporte marginal de variables macroeconómicas adicionales. Los controles que estaremos usando son los siguientes:

  • TCU: Capacity Utilization: Total Industry (Percent of Capacity)
  • USGOVT: All Employees: Government (Thousands of Persons)
  • UNRATE: Civilian Unemployment Rate (Percent)
  • DGDSRG3Q086SBEA: Personal consumption expenditures: Goods (chain-type price index)
  • GS10TB3Mx: 10-Year Treasury Constant Maturity Minus 3-Month Treasury Bill, secondary market (Percent)
  • CPF3MTB3Mx: 3-Month Commercial Paper Minus 3-Month Treasury Bill, secondary market (Percent)
  • BOGMBASEREALx: St. Louis Adjusted Monetary Base (Billions of 1982-84 Dollars), deflated by CPI
controls <- c("TCU","USGOVT","UNRATE","DGDSRG3Q086SBEA",
                  "GS10TB3Mx","CPF3MTB3Mx","BOGMBASEREALx")

# Estandarizamos variables de control  
df_reg_sub <- df_reg_sub %>%
 mutate(across(all_of(controls), ~ as.numeric(scale(.x))))

# Fórmula    
form_v3 <- bf( FEDFUNDS ~ i_lag1 + pi_gap + y_gap + TCU + USGOVT + UNRATE + DGDSRG3Q086SBEA + GS10TB3Mx + CPF3MTB3Mx + BOGMBASEREALx )

priors_v3 <- c(
  # Intercepto
  prior(normal(0, 5.0), class = "Intercept"),
  
  # LASSO general para todos los betas - equivale a 1/lambda, así que si ->0 mayor es la penalización (shrinkage)
  prior(double_exponential(0, 0.2), class = "b"),
  
  # Núcleo BIS con priors normales fuertes
  prior(normal(0.74, 0.10), class = "b", coef = "i_lag1"),
  prior(normal(2.11, 0.10), class = "b", coef = "pi_gap"),
  prior(normal(0.26, 0.05), class = "b", coef = "y_gap"),
  
  # Sigma débil
  prior(student_t(3, 0, 10), class = "sigma")
)

# Ajuste
set.seed(42)

taylor_bayes_v3_brms <- brm(
  formula = form_v3,
  data    = df_reg_sub,
  family  = gaussian(),
  prior   = priors_v3,
  chains = 4,
  iter   = 15000,
  warmup = 5000,
  cores  = 4,
  seed   = 42,
  sample_prior = "yes"
)
summary(taylor_bayes_v3_brms)
##  Family: gaussian 
##   Links: mu = identity 
## Formula: FEDFUNDS ~ i_lag1 + pi_gap + y_gap + TCU + USGOVT + UNRATE + DGDSRG3Q086SBEA + GS10TB3Mx + CPF3MTB3Mx + BOGMBASEREALx 
##    Data: df_reg_sub (Number of observations: 108) 
##   Draws: 4 chains, each with iter = 15000; warmup = 5000; thin = 1;
##          total post-warmup draws = 40000
## 
## Regression Coefficients:
##                 Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## Intercept           1.98      0.35     1.28     2.67 1.00    29664    27505
## i_lag1              0.62      0.05     0.52     0.73 1.00    29521    27363
## pi_gap              1.88      0.10     1.69     2.07 1.00    42749    29402
## y_gap               0.25      0.05     0.16     0.34 1.00    40189    28194
## TCU                -0.08      0.12    -0.33     0.14 1.00    31117    26653
## USGOVT             -0.43      0.33    -1.14     0.09 1.00    22040    22937
## UNRATE              0.33      0.20    -0.02     0.73 1.00    31428    27282
## DGDSRG3Q086SBEA     0.17      0.21    -0.16     0.64 1.00    29687    23267
## GS10TB3Mx          -0.48      0.14    -0.74    -0.21 1.00    28764    27334
## CPF3MTB3Mx          0.08      0.11    -0.12     0.31 1.00    37471    25324
## BOGMBASEREALx      -0.15      0.22    -0.63     0.24 1.00    30530    24019
## 
## Further Distributional Parameters:
##       Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## sigma     0.89      0.07     0.76     1.03 1.00    33692    29176
## 
## Draws were sampled using sampling(NUTS). For each parameter, Bulk_ESS
## and Tail_ESS are effective sample size measures, and Rhat is the potential
## scale reduction factor on split chains (at convergence, Rhat = 1).

La estimación bayesiana con prior LASSO muestra que los coeficientes principales de la Regla de Taylor (inercia, brecha de inflación y output gap) se mantienen significativos y con magnitudes consistentes con las versiones anteriores. En cambio, la mayoría de las variables de control presentan distribuciones posteriores centradas cerca de cero y con intervalos amplios, indicando que el shrinkage penaliza fuertemente su aporte marginal. Solo GS10TB3Mx muestra evidencia moderada de efecto. En conjunto, el modelo confirma que la dinámica de tasas está explicada casi por completo por los componentes centrales de la regla.

Visualización de Resultados

# Visualizacion de controles
controls_b <- c("b_TCU","b_USGOVT","b_UNRATE","b_DGDSRG3Q086SBEA",
                "b_GS10TB3Mx","b_CPF3MTB3Mx","b_BOGMBASEREALx")

as_draws_df(taylor_bayes_v3_brms) %>%
  dplyr::select(all_of(controls_b)) %>%
  pivot_longer(everything(), names_to="term", values_to="value") %>%
  ggplot(aes(x=value, y=term)) +
  stat_halfeye(.width = 0.95) +
  geom_vline(xintercept=0, linetype="dashed") +
  labs(title="Controles con prior LASSO: posterior",
       subtitle="Los que quedan concentrados en 0 no aportan",
       x="Coeficiente", y=NULL) +
  theme_minimal()

Este gráfico muestra la distribución posterior de los coeficientes asociados a las variables de control bajo el prior LASSO. Las distribuciones que quedan concentradas alrededor de cero indican que, dado el shrinkage aplicado, esas variables no aportan información relevante.

# Comparación de Lambdas

# grilla de scales (b): de débil a fuerte
b_grid <- c(1.0, 0.7, 0.5, 0.3, 0.2, 0.15, 0.1, 0.07, 0.05, 0.025)

# Funcion que arma priors con cada b
make_priors_v3 <- function(b_scale){
  
  laplace_str <- paste0("double_exponential(0, ", b_scale, ")")
  
  c(
    # Intercepto
    set_prior("normal(0, 5.0)", class = "Intercept"),
    
    # LASSO general para todos los coeficientes b
    set_prior(laplace_str, class = "b"),
    
    # Sobrescribo núcleo BIS con normales fuertes
    set_prior("normal(0.74, 0.10)", class = "b", coef = "i_lag1"),
    set_prior("normal(2.11, 0.10)", class = "b", coef = "pi_gap"),
    set_prior("normal(0.26, 0.05)", class = "b", coef = "y_gap"),
    
    # sigma débil
    set_prior("student_t(3, 0, 10)", class = "sigma")
  )
}


# Reestimar modelos para cada b

fits_v3 <- map(b_grid, ~ brm(
  formula = form_v3,
  data    = df_reg_sub,
  family  = gaussian(),
  prior   = make_priors_v3(.x),
  chains  = 4,
  iter    = 4000,
  warmup  = 1000,
  cores   = 4,
  seed    = 42,
  refresh = 0 
))


names(fits_v3) <- paste0("b_", b_grid)

# Extraer cofiecientes de controles y construir el path
core_vars <- c("i_lag1", "pi_gap", "y_gap")
core_b <- paste0("b_", core_vars)

# obtiene nombres b_ reales desde cualquier fit brms
get_controls_b <- function(fit) {
  b_names <- grep("^b_", posterior::variables(as_draws_df(fit)), value = TRUE)
  setdiff(b_names, core_b)
}

controls_b <- get_controls_b(fits_v3[[1]])  # usar el primer fit como referencia
controls_b

# función para extraer el coeficiente "moda" del vector
get_mode <- function(x) {
  d <- density(x)
  d$x[which.max(d$y)]
}


paths_df_map <- map2_dfr(fits_v3, b_grid, ~ {
  # extraer draws de los coeficientes de controles
  draws <- as_draws_df(.x) %>%
    dplyr::select(all_of(controls_b)) %>%
    pivot_longer(everything(), names_to="term", values_to="value") %>%
    # excluir intercepto
    filter(term != "b_Intercept") %>%
    group_by(term) %>%
    summarise(
      map = get_mode(value),
      .groups="drop"
    )
  
  draws %>%
    mutate(
      b_scale = .y,
      log_lambda = log(1/.y)   # lambda clásica = 1/b
    )
})

# Graficar coeficient path con MAP (sin intercepto)
ggplot(paths_df_map, aes(x = log_lambda, y = map, color = term)) +
  geom_line(linewidth = 0.9) +
  geom_hline(yintercept = 0, linetype = "dashed") +
  labs(
    title = "Coeficient paths para controles (v3)",
    subtitle = "A mayor log(lambda) = mayor shrinkage (b más chico)",
    x = "log(lambda)  [lambda = 1 / b_scale]",
    y = "Moda posterior del coeficiente"
  ) +
  theme_minimal() +
  theme(legend.title = element_blank())

En este caso, se puede ver cómo cambian los coeficientes de las variables de control a medida que aumenta la penalización LASSO. A medida que el shrinkage se intensifica, todos los coeficientes se contraen progresivamente hacia cero. Las variables cuyos coeficientes caen rápidamente indican menor relevancia explicativa, mientras que las que resisten más tiempo alejadas de cero son las que el modelo considera relativamente más informativas.

LS0tDQp0aXRsZTogIkluZmVyZW5jaWEgQmF5ZXNpYW5hIGFwbGljYWRhIGEgSGlww7N0ZXNpcyBNYWNyb2Vjb27Ds21pY2FzIg0KYXV0aG9yOiAiUGVkcm8gQm9zY2gsIE5pY29sYXMgQ2FyaWNhdGksIEFndXN0w61uIFJpdmFzIg0KZGF0ZTogIjIwLzExLzIwMjUiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgdG9jOiB0cnVlDQogICAgdG9jX2Zsb2F0OiB0cnVlDQogICAgY29kZV9mb2xkaW5nOiBzaG93DQogICAgZGZfcHJpbnQ6IHBhZ2VkDQogICAgdGhlbWU6IHVuaXRlZA0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCiAgcGRmX2RvY3VtZW50Og0KICAgIHRvYzogdHJ1ZQ0Kc3VidGl0bGU6IFRQIOKAkyBFbmZvcXVlIEVzdGFkw61zdGljbyBkZWwgQXByZW5kaXphamUNCi0tLQ0KDQojIE9iamV0aXZvDQoNCkVsIG9iamV0aXZvIGRlIGVzdGUgaW5mb3JtZSBlcyBlc3RpbWFyIGxhIHJlZ2xhIGRlIFRheWxvciB1dGlsaXphbmRvIG3DqXRvZG9zIHRyYWRpY2lvbmFsZXMgKE9MUykgeSBtb2RlbG9zIGJheWVzaWFub3MuIFBhcmEgbGEgZXNwZWNpZmljYWNpw7NuIGRlIGxvcyBwcmlvcnMgeSBjaWVydG9zIHBhcsOhbWV0cm9zIGRlIHJlZmVyZW5jaWEgc2UgdXRpbGl6YW4gdmFsb3JlcyBkb2N1bWVudGFkb3MgZW4gZGlzdGludG9zIHRyYWJham9zIGFjYWTDqW1pY29zLCBlbiBwYXJ0aWN1bGFyIHVuIGFydMOtY3VsbyBkZWwgQklTIChCYW5rIGZvciBJbnRlcm5hdGlvbmFsIFNldHRsZW1lbnRzKSwgcXVlIHByZXNlbnRhIGluZm9ybWFjacOzbiBhY2VyY2EgZGUgcG9sw610aWNhIG1vbmV0YXJpYS4NCg0KIyBDb25maWd1cmFjacOzbiBJbmljaWFsDQoNCiMjIEltcG9ydGFjacOzbiBkZSBsaWJyZXLDrWFzDQoNClBhcmEgZWwgZGVzYXJyb2xsbyBkZWwgYW7DoWxpc2lzIHNlIHJlcXVpZXJlIGxhIGNhcmdhIGRlIGxpYnJlcsOtYXMgZXNwZWPDrWZpY2FzIHBhcmEgZWwgbWFuZWpvIHkgdHJhbnNmb3JtYWNpw7NuIGRlIGRhdG9zLCBlbCB0cmFiYWpvIGNvbiBmZWNoYXMsIGxhIGVzdGltYWNpw7NuIGRlIG1vZGVsb3MgYmF5ZXNpYW5vcyB5IGxhIGdlbmVyYWNpw7NuIGRlIGdyw6FmaWNvcy4NCg0KYGBge3IgbGliLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KbGlicmFyeShsdWJyaWRhdGUpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShiYXllc3JlZykgICANCmxpYnJhcnkoTUNNQ3BhY2spDQpsaWJyYXJ5KHRpZHlyKQ0KbGlicmFyeShjbWRzdGFucikNCmxpYnJhcnkoYnJtcykNCmxpYnJhcnkoYnJvb20pDQpsaWJyYXJ5KHRpZHliYXllcykNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoZ2dkaXN0KQ0KbGlicmFyeShiYXllc3Bsb3QpDQpsaWJyYXJ5KHBvc3RlcmlvcikNCmxpYnJhcnkocGxvdGx5KQ0KbGlicmFyeShncmlkRXh0cmEpDQpsaWJyYXJ5KHNjYWxlcykNCmxpYnJhcnkocmxhbmcpDQpsaWJyYXJ5KHB1cnJyKQ0KYGBgDQoNCiMjIEltcG9ydGFjacOzbiBkZWwgZGF0YXNldA0KDQpTZSBkZWZpbmUgZWwgZGlyZWN0b3JpbyBkZSB0cmFiYWpvIHkgbHVlZ28gc2UgaW1wb3J0YSBlbCBhcmNoaXZvIHF1ZSBjb250aWVuZSBsYXMgc2VyaWVzIG1hY3JvZWNvbsOzbWljYXMgdXRpbGl6YWRhcyBlbiBlbCBhbsOhbGlzaXMuDQoNCmBgYHtyIGltcH0NCnNldHdkKCJHOi9NeSBEcml2ZS9UUCBFRUEiKQ0KDQpkYXRhc2V0IDwtIHJlYWQuY3N2KCJHOi9NeSBEcml2ZS9UUCBFRUEvMjAyNS0wOS1RRC5jc3YiKQ0KDQpoZWFkKGRhdGFzZXQpDQoNCmdkcHBvdCA8LSByZWFkLmNzdigiR0RQUE9ULmNzdiIpDQoNCmhlYWQoZ2RwcG90KQ0KDQpgYGANCg0KIyMgVHJhbnNmb3JtYWNpw7NuIGRlIGRhdG9zDQpTZSByZWFsaXphbiBjb3JyZWNjaW9uZXMgbmVjZXNhcmlhcyBhbnRlcyBkZWwgYW7DoWxpc2lzIHkgc2UgbWVyZ2VhbiBsb3MgZGF0YXNldHMuDQpgYGB7ciB0cn0NCmRhdGFzZXQgPC0gZGF0YXNldFstYygxLCAyKSwgXSAgIyBTZSBlbGltaW5hbiBmaWxhcyBpbmljaWFsZXMNCmRhdGFzZXQkc2FzZGF0ZSA8LSBhcy5EYXRlKGRhdGFzZXQkc2FzZGF0ZSwgZm9ybWF0ID0gIiVtLyVkLyVZIikgICMgQ29udmVyc2nDs24gYSBmZWNoYXMNCmRhdGFzZXQkcXVhcnRlcl9sYWJlbCA8LSBwYXN0ZTAoeWVhcihkYXRhc2V0JHNhc2RhdGUpLCAiUSIsIHF1YXJ0ZXIoZGF0YXNldCRzYXNkYXRlKSkgIyBFdGlxdWV0YSB0cmltZXN0cmFsDQpkYXRhc2V0IDwtIGRhdGFzZXRbb3JkZXIoZGF0YXNldCRzYXNkYXRlKSwgXSAgICMgT3JkZW4gdGVtcG9yYWwNCmRhdGFzZXQkdGltZV9pbmRleCA8LSBzZXFfbGVuKG5yb3coZGF0YXNldCkpICAgICMgw41uZGljZSBkZSB0aWVtcG8NCmRhdGFzZXQgPC0gZGF0YXNldCAlPiUgcmVsb2NhdGUocXVhcnRlcl9sYWJlbCwgdGltZV9pbmRleCwgLmFmdGVyID0gMSkgICMgUmVvcmdhbml6YWNpw7NuIGRlIGNvbHVtbmFzDQpgYGANCmBgYHtyIHRyMn0NCmdkcHBvdCRvYnNlcnZhdGlvbl9kYXRlIDwtIGdzdWIoIi0iLCAiLyIsIGdkcHBvdCRvYnNlcnZhdGlvbl9kYXRlKQ0KZ2RwcG90JG9ic2VydmF0aW9uX2RhdGUgPC0gYXMuRGF0ZShnZHBwb3Qkb2JzZXJ2YXRpb25fZGF0ZSwgZm9ybWF0ID0gIiVtLyVkLyVZIikgIyBDb252ZXJzacOzbiBhIGZlY2hhcw0KDQpkYXRhc2V0IDwtIGRhdGFzZXQgJT4lDQogIGxlZnRfam9pbigNCiAgICBnZHBwb3QsDQogICAgYnkgPSBjKCJzYXNkYXRlIiA9ICJvYnNlcnZhdGlvbl9kYXRlIikNCiAgKQ0KDQogI1NlbGVjY2lvbm8gdmFyaWFibGVzDQpkZiA8LSBkYXRhc2V0ICU+JQ0KICBkcGx5cjo6c2VsZWN0KA0KICAgIHNhc2RhdGUsDQogICAgcXVhcnRlcl9sYWJlbCwNCiAgICB0aW1lX2luZGV4LA0KICAgIFBDRUNUUEksDQogICAgR0RQQzEsDQogICAgR0RQUE9ULA0KICAgIEZFREZVTkRTLA0KICAgIFRDVSwgI3ZhcmlhYmxlIGRlIGNvbnRyb2wNCiAgICBVU0dPVlQsICN2YXJpYWJsZSBkZSBjb250cm9sDQogICAgVU5SQVRFLCAjdmFyaWFibGUgZGUgY29udHJvbA0KICAgIERHRFNSRzNRMDg2U0JFQSwgI3ZhcmlhYmxlIGRlIGNvbnRyb2wNCiAgICBHUzEwVEIzTXgsICN2YXJpYWJsZSBkZSBjb250cm9sDQogICAgQ1BGM01UQjNNeCwgI3ZhcmlhYmxlIGRlIGNvbnRyb2wNCiAgICBCT0dNQkFTRVJFQUx4ICN2YXJpYWJsZSBkZSBjb250cm9sDQogICkNCg0KIyBGaWx0cmFyIGVsIHJhbmdvIGRlIGZlY2hhcyBwYXJhIGxhcyBzZXJpZXMNCmRmX2ZpbHRlcmVkIDwtIGRmICU+JQ0KICBmaWx0ZXIoc2FzZGF0ZSA+IGFzLkRhdGUoIjE5ODAtMDEtMDEiKSAmIHNhc2RhdGUgPCBhcy5EYXRlKCIyMDA3LTAxLTAxIikpDQoNCmhlYWQoZGZfZmlsdGVyZWQpDQpgYGANCg0KIyBBbsOhbGlzaXMgRXhwbG9yYXRvcmlvDQoNCkxhIFJlZ2xhIGRlIFRheWxvciBlcyB1biBtb2RlbG8gYW1wbGlhbWVudGUgdXRpbGl6YWRvIGVuIG1hY3JvZWNvbm9tw61hIHBhcmEgZGVzY3JpYmlyIGPDs21vIGRlYmVyw61hIHJlYWNjaW9uYXIgbGEgcG9sw610aWNhIG1vbmV0YXJpYSBhbnRlIGRlc3bDrW9zIGRlIGxhIGluZmxhY2nDs24gcmVzcGVjdG8gZGUgc3UgbWV0YSB5IGFudGUgZmx1Y3R1YWNpb25lcyBkZWwgcHJvZHVjdG8gcmVzcGVjdG8gZGUgc3Ugbml2ZWwgcG90ZW5jaWFsLiBQYXJhIGVzdGltYXJsYSBlbXDDrXJpY2FtZW50ZSwgc2UgcmVxdWllcmUgY29uc3RydWlyIHVuYSBzZXJpZSBkZSB2YXJpYWJsZXMgbWFjcm9lY29uw7NtaWNhcyBjbGF2ZTogZWwgKm91dHB1dCBnYXAqLCBsYSBpbmZsYWNpw7NuIHRyaW1lc3RyYWwgeSBsYSBicmVjaGEgZGUgaW5mbGFjacOzbiAoKmluZmxhdGlvbiBnYXAqKS4NCg0KIyMgU2VsZWNjacOzbiBkZSB2YXJpYWJsZXMgcmVsZXZhbnRlcw0KRW4gcHJpbWVyIGx1Z2FyLCBzZSBjb25zdHJ1eWUgdW4gc3ViY29uanVudG8gZGVsIGRhdGFzZXQgb3JpZ2luYWwgY29uc2VydmFuZG8gw7puaWNhbWVudGUgbGFzIHNlcmllcyBuZWNlc2FyaWFzIHBhcmEgZWwgYW7DoWxpc2lzLiBMYXMgcHJpbmNpcGFsZXMgdmFyaWFibGVzIG1hY3JvZWNvbsOzbWljYXMgdXRpbGl6YWRhcyBzb246DQoNCi0gKipQQ0VDVFBJKiog4oCUIMONbmRpY2UgZGUgUHJlY2lvcyBkZSBsb3MgR2FzdG9zIGVuIENvbnN1bW8gUGVyc29uYWw6IGluZGljYWRvciBkZSBpbmZsYWNpw7NuIHV0aWxpemFkbyBwb3IgbGEgUmVzZXJ2YSBGZWRlcmFsIGRlIEVzdGFkb3MgVW5pZG9zLiBNaWRlIGxhIGV2b2x1Y2nDs24gZGVsIG5pdmVsIGRlIHByZWNpb3MgZGUgYmllbmVzIHkgc2VydmljaW9zIGNvbnN1bWlkb3MgcG9yIGxvcyBob2dhcmVzLg0KLSAqKkdEUEMxKiog4oCUIFByb2R1Y3RvIEJydXRvIEludGVybm8gUmVhbDogbWlkZSBlbCBuaXZlbCBkZSBhY3RpdmlkYWQgZWNvbsOzbWljYSBhanVzdGFkbyBwb3IgaW5mbGFjacOzbiB5IHJlZmxlamEgbGEgY2FudGlkYWQgcmVhbCBkZSBiaWVuZXMgeSBzZXJ2aWNpb3MgcHJvZHVjaWRvcyBlbiBsYSBlY29ub23DrWEuDQotICoqR0RQUE9UKiog4oCUIFByb2R1Y3RvIFBvdGVuY2lhbDogcmVwcmVzZW50YSBlbCBuaXZlbCBkZSBwcm9kdWNjacOzbiBxdWUgbGEgZWNvbm9tw61hIHBvZHLDrWEgc29zdGVuZXIgZGUgbWFuZXJhIHNvc3RlbmlibGUsIHNpbiBnZW5lcmFyIHByZXNpb25lcyBpbmZsYWNpb25hcmlhcyBwZXJzaXN0ZW50ZXMuDQotICoqRkVERlVORFMqKiDigJQgVGFzYSBkZSBGb25kb3MgRmVkZXJhbGVzOiB0YXNhIGRlIGludGVyw6lzIGRlIHJlZmVyZW5jaWEgZmlqYWRhIHBvciBsYSBSZXNlcnZhIEZlZGVyYWwuDQpgYGB7ciBzZWxlY3RfdmFycywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCg0KIyAxKSBQcm9kdWN0byAoR0RQQzEgeSBHRFBQT1QpIGp1bnRvcw0KZGZfcHJvZHVjdG9zIDwtIGRmX2ZpbHRlcmVkICU+JQ0KICBkcGx5cjo6c2VsZWN0KHNhc2RhdGUsIEdEUEMxLCBHRFBQT1QpICU+JQ0KICBwaXZvdF9sb25nZXIoY29scyA9IGMoR0RQQzEsIEdEUFBPVCksIG5hbWVzX3RvID0gInZhcmlhYmxlIiwgdmFsdWVzX3RvID0gInZhbHVlIikNCg0KcDEgPC0gZ2dwbG90KGRmX3Byb2R1Y3RvcywgYWVzKHggPSBzYXNkYXRlLCB5ID0gdmFsdWUsIGNvbG9yID0gdmFyaWFibGUpKSArDQogIGdlb21fbGluZShzaXplID0gMSkgKw0KICBsYWJzKHRpdGxlID0gIlByb2R1Y3RvIEludGVybm8gQnJ1dG8gUmVhbCB5IFByb2R1Y3RvIFBvdGVuY2lhbCIsDQogICAgICAgeCA9ICJGZWNoYSIsDQogICAgICAgeSA9ICJWYWxvciIpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUobGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQ0KDQojIDIpIFRhc2EgZGUgaW50ZXLDqXMgRkVERlVORFMgc29sYQ0KZGZfdGFzYSA8LSBkZl9maWx0ZXJlZCAlPiUNCiAgZHBseXI6OnNlbGVjdChzYXNkYXRlLCBGRURGVU5EUykNCg0KcDIgPC0gZ2dwbG90KGRmX3Rhc2EsIGFlcyh4ID0gc2FzZGF0ZSwgeSA9IEZFREZVTkRTKSkgKw0KICBnZW9tX2xpbmUoY29sb3IgPSAic3RlZWxibHVlIiwgc2l6ZSA9IDEpICsNCiAgbGFicyh0aXRsZSA9ICJUYXNhIGRlIEZvbmRvcyBGZWRlcmFsZXMgKEZFREZVTkRTKSIsDQogICAgICAgeCA9ICJGZWNoYSIsDQogICAgICAgeSA9ICJUYXNhICglKSIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQoNCiMgTW9zdHJhciBsb3MgZ3LDoWZpY29zIHVubyBkZWJham8gZGVsIG90cm8NCmdyaWQuYXJyYW5nZShwMSwgcDIsIG5jb2wgPSAxKQ0KDQpgYGANCg0KIyMgT3V0cHV0IEdhcA0KRWwgb3V0cHV0IGdhcCBtaWRlIGVsIGRlc3bDrW8gcG9yY2VudHVhbCBkZWwgUHJvZHVjdG8gSW50ZXJubyBCcnV0byByZWFsIChHRFBDMSkgcmVzcGVjdG8gZGUgc3Ugbml2ZWwgcG90ZW5jaWFsIChHRFBQT1QpLiBMYSBzaWd1aWVudGUgdHJhbnNmb3JtYWNpw7NuIGNhbGN1bGEgZXN0YSBicmVjaGEgZW4gcHVudG9zIHBvcmNlbnR1YWxlczoNCmBgYHtyIG91dHB1dF9nYXB9DQpkZiA8LSBkZiAlPiUNCiAgbXV0YXRlKA0KICAgIHlfZ2FwID0gMTAwICogKEdEUEMxIC0gR0RQUE9UKSAvIEdEUFBPVCkNCg0KDQojIFNlbGVjY2lvbmFtb3MgbGEgdmFyaWFibGUgeSBwYXNhbW9zIGEgZm9ybWF0byBsYXJnbw0KZGZfbG9uZyA8LSBkZiAlPiUNCiAgZHBseXI6OnNlbGVjdChzYXNkYXRlLHlfZ2FwKSAlPiUNCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSAtc2FzZGF0ZSwgbmFtZXNfdG8gPSAidmFyaWFibGUiLCB2YWx1ZXNfdG8gPSAidmFsdWUiKQ0KDQpkZl9sb25nIDwtIGRmX2xvbmcgJT4lDQogIGZpbHRlcihzYXNkYXRlID4gYXMuRGF0ZSgiMTk4MC0wMS0wMSIpICYgc2FzZGF0ZSA8IGFzLkRhdGUoIjIwMDctMDEtMDEiKSApDQoNCiMgR3LDoWZpY28gaGlzdMOzcmljbw0KZ2dwbG90KGRmX2xvbmcsIGFlcyh4ID0gc2FzZGF0ZSwgeSA9IHZhbHVlLCBjb2xvciA9IHZhcmlhYmxlKSkgKw0KICBnZW9tX2xpbmUoc2l6ZSA9IDEpICsNCiAgZmFjZXRfd3JhcCh+dmFyaWFibGUsIHNjYWxlcyA9ICJmcmVlX3kiLCBuY29sID0gMikgKw0KICBsYWJzKHRpdGxlID0gIlNlcmllcyBoaXN0b3JpY2FzIGRlbCB5X2dhcCIsDQogICAgICAgeCA9ICJGZWNoYSIsDQogICAgICAgeSA9ICJWYWxvciIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQoNCmBgYA0KDQojIyBJbmZsYXRpb24gR2FwDQpMYSBicmVjaGEgZGUgaW5mbGFjacOzbiBtaWRlIGVsIGRlc3bDrW8gZW50cmUgbGEgaW5mbGFjacOzbiBvYnNlcnZhZGEgeSBsYSBtZXRhIGltcGzDrWNpdGEgZGUgbGEgUmVzZXJ2YSBGZWRlcmFsLiBQYXJhIGVzdGUgdHJhYmFqbyBzZSB1dGlsaXphIHVuIG9iamV0aXZvIGFudWFsIGRlbCAyJSwgcXVlIGVuIGZyZWN1ZW5jaWEgdHJpbWVzdHJhbCBlcXVpdmFsZSBhcHJveGltYWRhbWVudGUgYSAwLDUlLiBMYSB2YXJpYWJsZSBwaV9nYXAgc2UgZGVmaW5lIGVudG9uY2VzIGNvbW8gbGEgZGlmZXJlbmNpYSBlbnRyZSBsYSBpbmZsYWNpw7NuIHRyaW1lc3RyYWwgZXN0aW1hZGEgYSBwYXJ0aXIgZGVsIMOtbmRpY2UgUENFIHkgZXN0YSBtZXRhLg0KDQpgYGB7ciBpbmZfZ2FwfQ0KIyBJbmZsYWNpb24gVHJpbWVzdHJhbCBvYmpldGl2bw0KcGlfc3Rhcl9xIDwtIDAuNQ0KDQojIEV4dHJhZW1vcyBkZWwgaW5kaWNlIGRlIHByZWNpb3MgbGEgaW5mbGFjaW9uIHRyaW1lc3RyYWwgY29uIGxhIGFwcm94aW1hY2lvbiBsb2ctZGlmZg0KZGYgPC0gZGYgJT4lDQogIGFycmFuZ2Uoc2FzZGF0ZSkgJT4lDQogIG11dGF0ZSgNCiAgICBpbmZsX3EgPSAxMDAgKiAobG9nKFBDRUNUUEkpIC0gZHBseXI6OmxhZyhsb2coUENFQ1RQSSksIDEpKSwgIyBpbmZsYWNpw7NuIHRyaW1lc3RyYWwgZW4gJSAoYXByb3ggbG9nLWRpZmYpDQogICAgcGlfZ2FwID0gaW5mbF9xIC0gcGlfc3Rhcl9xDQogICkgJT4lDQogIGRyb3BfbmEocGlfZ2FwKQ0KDQojIFNlbGVjY2lvbmFtb3MgbGEgdmFyaWFibGUgeSBwYXNhbW9zIGEgZm9ybWF0byBsYXJnbw0KZGZfbG9uZyA8LSBkZiAlPiUNCiAgZHBseXI6OnNlbGVjdChzYXNkYXRlLHBpX2dhcCkgJT4lDQogIHBpdm90X2xvbmdlcihjb2xzID0gLXNhc2RhdGUsIG5hbWVzX3RvID0gInZhcmlhYmxlIiwgdmFsdWVzX3RvID0gInZhbHVlIikNCg0KZGZfbG9uZyA8LSBkZl9sb25nICU+JQ0KICBmaWx0ZXIoc2FzZGF0ZSA+IGFzLkRhdGUoIjE5ODAtMDEtMDEiKSAmIHNhc2RhdGUgPCBhcy5EYXRlKCIyMDA3LTAxLTAxIikgKQ0KDQojIEdyw6FmaWNvIGhpc3TDs3JpY28NCmdncGxvdChkZl9sb25nLCBhZXMoeCA9IHNhc2RhdGUsIHkgPSB2YWx1ZSwgY29sb3IgPSB2YXJpYWJsZSkpICsNCiAgZ2VvbV9saW5lKHNpemUgPSAxKSArDQogIGZhY2V0X3dyYXAofnZhcmlhYmxlLCBzY2FsZXMgPSAiZnJlZV95IiwgbmNvbCA9IDIpICsNCiAgbGFicyh0aXRsZSA9ICJTZXJpZXMgaGlzdG9yaWNhcyBkZWwgZGVzdmlvIGRlIGxhIGluZmxhY2lvbiByZXNwZWN0byBhIGxhIG9iamV0aXZhIiwNCiAgICAgICB4ID0gIkZlY2hhIiwNCiAgICAgICB5ID0gIlZhbG9yIikgKw0KICB0aGVtZV9taW5pbWFsKCkNCg0KYGBgDQoNCiMjIEluZXJjaWEgZGUgbGEgdGFzYSBkZSBpbnRlcsOpcw0KUGFyYSBjYXB0dXJhciBlbCBjb21wb3J0YW1pZW50byBncmFkdWFsIGRlIGxhIHBvbMOtdGljYSBtb25ldGFyaWEsIHNlIGluY29ycG9yYSBsYSB0YXNhIGRlIGZvbmRvcyBmZWRlcmFsZXMgcmV6YWdhZGEgdW4gcGVyw61vZG8gKGlfbGFnMSkuIEVzdGEgdmFyaWFibGUgcmVmbGVqYSBsYSBpbmVyY2lhIHTDrXBpY2EgY29uIGxhIHF1ZSBsYSBSZXNlcnZhIEZlZGVyYWwgYWp1c3RhIGxhIHRhc2EgZGUgaW50ZXLDqXMsIGRhZG8gcXVlIGxvcyBjYW1iaW9zIHN1ZWxlbiByZWFsaXphcnNlIGRlIG1hbmVyYSBwcm9ncmVzaXZhIHkgbm8gYWJydXB0YSBkZSB1biB0cmltZXN0cmUgYSBvdHJvLiANCmBgYHtyIGluZXJjaWF9DQojIENvbnRydWltb3MgbGFzIHZhcmlhYmxlcyBsYWdzIGRlIGludGVyZXMgeSBjYW1iaW8gZW4gbGEgdGFzYSBkZSBpbnRlcmVzDQpkZiA8LSBkZiAlPiUNCiAgYXJyYW5nZShzYXNkYXRlKSAlPiUNCiAgbXV0YXRlKA0KICAgIGlfbGFnMSAgID0gZHBseXI6OmxhZyhGRURGVU5EUywgMSksICMgdGFzYSByZXphZ2FkYSAxDQogICAgZGVsdGFfaSAgPSBGRURGVU5EUyAtIGlfbGFnMSAjIGNhbWJpbyBlbiBsYSB0YXNhDQogICkgJT4lDQogIGRyb3BfbmEoaV9sYWcxLCBkZWx0YV9pKQ0KDQpkZl9sb25nIDwtIGRmICU+JQ0KICBkcGx5cjo6c2VsZWN0KHNhc2RhdGUsIGRlbHRhX2ksIEZFREZVTkRTKSAlPiUNCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSAtc2FzZGF0ZSwgbmFtZXNfdG8gPSAidmFyaWFibGUiLCB2YWx1ZXNfdG8gPSAidmFsdWUiKSAlPiUNCiAgZmlsdGVyKHNhc2RhdGUgPiBhcy5EYXRlKCIxOTgwLTAxLTAxIikgJiBzYXNkYXRlIDwgYXMuRGF0ZSgiMjAwNy0wMS0wMSIpKSAlPiUNCiAgbXV0YXRlKA0KICAgIHZhcmlhYmxlID0gcmVjb2RlKHZhcmlhYmxlLA0KICAgICAgICAgICAgICAgICAgICAgIEZFREZVTkRTID0gIkZFREZVTkRTIiwNCiAgICAgICAgICAgICAgICAgICAgICBkZWx0YV9pICA9ICJEZWx0YV9pIiksDQogICAgdmFyaWFibGUgPSBmYWN0b3IodmFyaWFibGUsIGxldmVscyA9IGMoIkZFREZVTkRTIiwgIkRlbHRhX2kiKSkNCiAgKQ0KDQpnZ3Bsb3QoZGZfbG9uZywgYWVzKHggPSBzYXNkYXRlLCB5ID0gdmFsdWUsIGNvbG9yID0gdmFyaWFibGUpKSArDQogIGdlb21fbGluZShzaXplID0gMSkgKw0KICBmYWNldF93cmFwKH52YXJpYWJsZSwgc2NhbGVzID0gImZyZWVfeSIsIG5yb3cgPSAyKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiU2VyaWVzIGhpc3TDs3JpY2FzIGRlIGxhIHRhc2EgZGUgaW50ZXLDqXMgeSBzdSBjYW1iaW8gcmVzcGVjdG8gYWwgdHJpbWVzdHJlIGFudGVyaW9yIiwNCiAgICB4ID0gIkZlY2hhIiwNCiAgICB5ID0gIlZhbG9yIiwNCiAgICBjb2xvciA9ICJWYXJpYWJsZXMiDQogICkgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwoDQogICAgdmFsdWVzID0gYygiRkVERlVORFMiID0gIiMxRjc3QjQiLCAiRGVsdGFfaSIgPSAiI0ZGN0YwRSIpLA0KICAgIGxhYmVscyA9IGMoIkZFREZVTkRTIiA9ICJGRURGVU5EUyIsICJEZWx0YV9pIiA9ICJEZWx0YV9pIikNCiAgKSArDQogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OmxhYmVsX251bWJlcihhY2N1cmFjeSA9IDAuMSkpICsNCiAgdGhlbWVfbWluaW1hbCgpDQoNCg0KYGBgDQoNCiMjIEFuw6FsaXNpcyBFc3RhZGlzdGljb3MgZGUgbGFzIHZhcmlhYmxlcw0KRW4gcHJpbWVyIGx1Z2FyLCBhbmFsaXphcmVtb3MgbGFzIHZhcmlhYmxlcyBhIHRyYXbDqXMgZGUgc3VzIG1lZGlkYXMgZGUgdGVuZGVuY2lhIHBhcmEgZWwgcGVyaW9kbyBlbiBjdWVzdGnDs24uDQpgYGB7ciBhbmFsaXNpcyBlc3RhZGlzdGljb30NCg0KZGZfZGVzYyA8LSBkZiAlPiUgZmlsdGVyKHNhc2RhdGUgPiBhcy5EYXRlKCIxOTgwLTAxLTAxIikgJiBzYXNkYXRlIDwgYXMuRGF0ZSgiMjAwNy0wMS0wMSIpICkNCg0KZGZfZGVzYyA8LSBkZl9kZXNjICU+JSBkcGx5cjo6c2VsZWN0KEdEUEMxLCBHRFBQT1QsIEZFREZVTkRTLCB5X2dhcCwgaW5mbF9xLCBwaV9nYXAsIGRlbHRhX2kpDQoNCnN1bW1hcnlfc3RhdHMgPC0gZGZfZGVzYyAlPiUNCiAgc3VtbWFyaXNlKA0KICAgIGFjcm9zcygNCiAgICAgIGV2ZXJ5dGhpbmcoKSwNCiAgICAgIGxpc3QoDQogICAgICAgIG1pbiAgPSB+bWluKC4gLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICBtYXggID0gfm1heCguICwgbmEucm0gPSBUUlVFKSwNCiAgICAgICAgbWVhbiA9IH5tZWFuKC4gLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICBzZCAgID0gfnNkKC4gLCBuYS5ybSA9IFRSVUUpDQogICAgICApLA0KICAgICAgLm5hbWVzID0gInsuY29sfV97LmZufSINCiAgICApDQogICkgJT4lDQogIHBpdm90X2xvbmdlcigNCiAgICBldmVyeXRoaW5nKCksDQogICAgbmFtZXNfdG8gPSBjKCJ2YXJpYWJsZSIsICJzdGF0IiksDQogICAgbmFtZXNfcGF0dGVybiA9ICIoLiopXyguKikiDQogICkgJT4lDQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBzdGF0LCB2YWx1ZXNfZnJvbSA9IHZhbHVlKSAlPiUNCiAgbXV0YXRlKGFjcm9zcyh3aGVyZShpcy5udW1lcmljKSwgfnJvdW5kKC4gLCAyKSkpDQoNCnN1bW1hcnlfc3RhdHMNCg0KDQpgYGANCkVuIHNlZ3VuZG8gbHVnYXIsIGFuYWxpemFyZW1vcyBsYSBldm9sdWNpw7NuIGRlIGxhcyB2YXJpYWJsZXMgZGVzZGUgZWwgZW5mb3F1ZSBoaXN0w7NyaWNvIGRlIGxhcyBzZXJpZXMgZGUgdGllbXBvLiBDb24gZWwgZmluIGRlIHJlcHJlc2VudGFybGFzIGRlIG1hbmVyYSBjb25qdW50YSBlbiB1biBtaXNtbyBncsOhZmljbywgcmVjdXJyaW1vcyBhbCBwcm9jZXNvIGRlIGVzdGFuZGFyaXphY2nDs24uIEVzdGUgcHJvY2VkaW1pZW50byB0cmFuc2Zvcm1hIGNhZGEgb2JzZXJ2YWNpw7NuIGVuIHVuIHrigJFzY29yZSwgZXMgZGVjaXIsIGVuIGxhIGNhbnRpZGFkIGRlIGRlc3ZpYWNpb25lcyBlc3TDoW5kYXIgcXVlIGRpY2hvIHZhbG9yIHNlIGVuY3VlbnRyYSBwb3IgZW5jaW1hIG8gcG9yIGRlYmFqbyBkZSBsYSBtZWRpYSBkZSBsYSB2YXJpYWJsZS4gRGUgZXN0YSBmb3JtYSwgbGFzIHRyZXMgc2VyaWVzIHF1ZWRhbiBleHByZXNhZGFzIGVuIHVuYSBlc2NhbGEgY29tw7puLCBsbyBxdWUgZmFjaWxpdGEgbGEgY29tcGFyYWNpw7NuIGRlIHN1cyBkaW7DoW1pY2FzIGEgbG8gbGFyZ28gZGVsIHRpZW1wby4NCg0KYGBge3IgZ3JhZmljb3MgaGlzdG9yaWNvc30NCg0KIyBTZWxlY2Npb25hbW9zIGxhcyB2YXJpYWJsZXMgeSBwYXNhbW9zIGEgZm9ybWF0byBsYXJnbw0KDQpkZl9ub3JtIDwtIGRmICU+JQ0KICBkcGx5cjo6c2VsZWN0KHNhc2RhdGUsIEZFREZVTkRTLCBwaV9nYXAsIHlfZ2FwKSAlPiUNCiAgbXV0YXRlKA0KICAgIEZFREZVTkRTX3ogPSBzY2FsZShGRURGVU5EUyksDQogICAgcGlfZ2FwX3ogICA9IHNjYWxlKHBpX2dhcCksDQogICAgeV9nYXBfeiAgICA9IHNjYWxlKHlfZ2FwKQ0KICApICU+JQ0KICBkcGx5cjo6c2VsZWN0KHNhc2RhdGUsIEZFREZVTkRTX3osIHBpX2dhcF96LCB5X2dhcF96KSAlPiUNCiAgcGl2b3RfbG9uZ2VyKA0KICAgIGNvbHMgPSAtc2FzZGF0ZSwNCiAgICBuYW1lc190byA9ICJ2YXJpYWJsZSIsDQogICAgdmFsdWVzX3RvID0gInZhbHVlIg0KICApICAlPiUgDQogICAgZmlsdGVyKHNhc2RhdGUgPiBhcy5EYXRlKCIxOTgwLTAxLTAxIikgJiBzYXNkYXRlIDwgYXMuRGF0ZSgiMjAwNy0wMS0wMSIpICkNCg0KcCA8LSBnZ3Bsb3QoZGZfbm9ybSwgYWVzKA0KICAgIHggPSBzYXNkYXRlLA0KICAgIHkgPSB2YWx1ZSwNCiAgICBjb2xvciA9IHZhcmlhYmxlLA0KICAgIGdyb3VwID0gdmFyaWFibGUsDQogICAgdGV4dCA9IHBhc3RlMCgNCiAgICAgICJGZWNoYTogIiwgZm9ybWF0KHNhc2RhdGUsICIlWS0lbSIpLCAiPGJyPiIsDQogICAgICAiVmFyaWFibGU6ICIsIGRwbHlyOjpyZWNvZGUodmFyaWFibGUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRkVERlVORFNfeiA9ICJUYXNhIEZlZCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGlfZ2FwX3ogICA9ICJJbmZsYXRpb24gZ2FwIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5X2dhcF96ICAgID0gIk91dHB1dCBnYXAiKSwgIjxicj4iLA0KICAgICAgIlZhbG9yOiAiLCBzcHJpbnRmKCIlLjJmIiwgdmFsdWUpDQogICAgKQ0KICApKSArDQogIGdlb21fbGluZShzaXplID0gMS4yKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiRXZvbHVjacOzbiBjb21wYXJhZGE6IHRhc2EgZGUgbGEgRmVkIHkgYnJlY2hhcyAobm9ybWFsaXphZGFzKSIsDQogICAgeCA9ICJGZWNoYSIsDQogICAgeSA9ICJWYWxvcmVzIG5vcm1hbGl6YWRvcyAoei1zY29yZSkiLA0KICAgIGNvbG9yID0gTlVMTA0KICApICsNCiAgc2NhbGVfY29sb3JfbWFudWFsKA0KICAgIHZhbHVlcyA9IGMoDQogICAgICBGRURGVU5EU196ID0gIiMxRjc3QjQiLA0KICAgICAgcGlfZ2FwX3ogICA9ICIjQUVDN0U4IiwNCiAgICAgIHlfZ2FwX3ogICAgPSAiIzk4REY4QSINCiAgICApLA0KICAgIGxhYmVscyA9IGMoIlRhc2EgRmVkIiwgIkluZmxhdGlvbiBnYXAiLCAiT3V0cHV0IGdhcCIpDQogICkgKw0KICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDE0KSArDQogIHRoZW1lKA0KICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLA0KICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA5KSwNCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIHNpemUgPSAxMiwgaGp1c3QgPSAwLjUpLA0KICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiksDQogICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KGNvbG9yID0gImdyYXkzMCIpDQogICkNCg0KZ2dwbG90bHkocCwgdG9vbHRpcCA9ICJ0ZXh0IikgJT4lDQogIGxheW91dCgNCiAgICBsZWdlbmQgPSBsaXN0KA0KICAgICAgb3JpZW50YXRpb24gPSAiaCIsDQogICAgICB4ID0gMC4yLA0KICAgICAgeSA9IDAuMQ0KICAgICkNCiAgKQ0KDQoNCmBgYA0KDQojIFJlZ3Jlc2lvbmVzDQoNCiMjIE9MUw0KU2UgZGV0ZXJtaW5hIHVuYSB2ZW50YW5hIHRlbXBvcmFsIHkgc2UgcHJvY2VkZSBjb24gbGEgcmVncmVzacOzbiB0cmFkaWNpb25hbC4NCmBgYHtyIHJlZ30NCmRmX3JlZ19zdWIgPC0gZGYgJT4lDQogIGZpbHRlcihzYXNkYXRlID4gYXMuRGF0ZSgiMTk4MC0wMS0wMSIpICYgc2FzZGF0ZSA8IGFzLkRhdGUoIjIwMDctMDEtMDEiKSApDQpgYGANCmBgYHtyIHJlZ19yZXN1bHR9DQp0YXlsb3Jfb2xzIDwtIGxtKA0KICBGRURGVU5EUyB+IGlfbGFnMSArIHBpX2dhcCArIHlfZ2FwLA0KICBkYXRhID0gZGZfcmVnX3N1Yg0KKQ0KDQpzdW1tYXJ5KHRheWxvcl9vbHMpDQpgYGANCkxhIGVzdGltYWNpw7NuIE9MUyBkZSBsYSBSZWdsYSBkZSBUYXlsb3IgYXJyb2phIHVuIGNvZWZpY2llbnRlIGRlIGluZXJjaWEgZWxldmFkbyBwYXJhIGxhIHRhc2EgZGUgaW50ZXLDqXMgKGlfbGFnMSDiiYggMCw4OSksIGxvIHF1ZSBpbmRpY2EgcXVlIGxhIFJlc2VydmEgRmVkZXJhbCBhanVzdGEgbGEgcG9sw610aWNhIG1vbmV0YXJpYSBkZSBtYW5lcmEgZ3JhZHVhbC4gVGFudG8gbGEgYnJlY2hhIGRlIGluZmxhY2nDs24gKHBpX2dhcCDiiYggMCw4OSkgY29tbyBlbCBvdXRwdXQgZ2FwICh5X2dhcCDiiYggMCwxNykgcHJlc2VudGFuIHNpZ25vcyBwb3NpdGl2b3MgeSBzb24gZXN0YWTDrXN0aWNhbWVudGUgc2lnbmlmaWNhdGl2b3MsIGVuIGzDrW5lYSBjb24gbGEgaWRlYSBkZSBxdWUgbGEgdGFzYSBkZSBmb25kb3MgZmVkZXJhbGVzIGF1bWVudGEgY3VhbmRvIGxhIGluZmxhY2nDs24gc2UgdWJpY2EgcG9yIGVuY2ltYSBkZSBsYSBtZXRhIHkgY3VhbmRvIGxhIGFjdGl2aWRhZCBzZSBzaXTDumEgcG9yIGVuY2ltYSBkZSBzdSBuaXZlbCBwb3RlbmNpYWwuIEVsIG1vZGVsbyBleGhpYmUgdW4gbXV5IGJ1ZW4gYWp1c3RlIChSwrIg4omIIDAsOTQpLCBwb3IgbG8gcXVlIGxhIGVzcGVjaWZpY2FjacOzbiBlc3RpbWFkYSBjYXB0dXJhIHJhem9uYWJsZW1lbnRlIGJpZW4gZWwgY29tcG9ydGFtaWVudG8gaGlzdMOzcmljbyBkZSBsYSBwb2zDrXRpY2EgbW9uZXRhcmlhIGVuIGVsIHBlcsOtb2RvIGNvbnNpZGVyYWRvLg0KDQojIyBSZWdyZXNpw7NuIEJheWVzaWFuYSAjMSAtIFByaW9ycyBEw6liaWxlcw0KQWRlbcOhcyBkZSBsYSBlc3RpbWFjacOzbiBtZWRpYW50ZSBNw61uaW1vcyBDdWFkcmFkb3MgT3JkaW5hcmlvcywgc2UgaW1wbGVtZW50w7MgdW5hIHZlcnNpw7NuIGJheWVzaWFuYSBkZSBsYSBSZWdsYSBkZSBUYXlsb3IuIEVzdGUgZW5mb3F1ZSBwZXJtaXRlIGNvbWJpbmFyIGxhIGluZm9ybWFjacOzbiBwcmVzZW50ZSBlbiBsb3MgZGF0b3MgY29uIGNvbm9jaW1pZW50byBwcmV2aW8gc29icmUgZWwgY29tcG9ydGFtaWVudG8gdMOtcGljbyBkZSBsYSBwb2zDrXRpY2EgbW9uZXRhcmlhLiBQYXJhIGVzdGEgcHJpbWVyYSBlc3BlY2lmaWNhY2nDs24gc2UgdXRpbGl6YXJvbiBwcmlvcnMgaW5mb3JtYXRpdmFzIGJhc2FkYXMgZW4gZXN0aW1hY2lvbmVzIHJlcG9ydGFkYXMgZW4gZXN0dWRpb3MgZGVsIEJJUywgcXVlIHJlZmxlamFuIHZhbG9yZXMgdMOtcGljb3MgcGFyYSBsYSBpbmVyY2lhIG1vbmV0YXJpYSB5IGxhcyByZXNwdWVzdGFzIGEgaW5mbGFjacOzbiB5IGFjdGl2aWRhZCBlY29uw7NtaWNhLg0KDQpgYGB7ciBiYXllc192MSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCnByaW9yc192MSA8LSBjKA0KICBwcmlvcihub3JtYWwoMCwgICAgNSksIGNsYXNzID0gIkludGVyY2VwdCIpLA0KICBwcmlvcihub3JtYWwoMC43NCwgMiksIGNsYXNzID0gImIiLCBjb2VmID0gImlfbGFnMSIpLA0KICBwcmlvcihub3JtYWwoMi4xMSwgMiksIGNsYXNzID0gImIiLCBjb2VmID0gInBpX2dhcCIpLA0KICBwcmlvcihub3JtYWwoMC4yNiwgMiksIGNsYXNzID0gImIiLCBjb2VmID0gInlfZ2FwIiksDQogIA0KIyBQcmlvciBkw6liaWwgcGFyYSBzaWdtYSAoZGVzdsOtbyBlc3TDoW5kYXIgcmVzaWR1YWwpDQogIHByaW9yKHN0dWRlbnRfdCgzLCAwLCAxMCksIGNsYXNzID0gInNpZ21hIikNCikNCg0Kc2V0LnNlZWQoNDIpDQoNCnRheWxvcl9iYXllc192MV9icm1zIDwtIGJybSgNCiAgRkVERlVORFMgfiBpX2xhZzEgKyBwaV9nYXAgKyB5X2dhcCwNCiAgZGF0YSAgID0gZGZfcmVnX3N1YiwNCiAgZmFtaWx5ID0gZ2F1c3NpYW4oKSwNCiAgcHJpb3IgID0gcHJpb3JzX3YxLA0KICBjaGFpbnMgPSA0LA0KICBpdGVyICAgPSAxNTAwMCwgICAjIHRvdGFsIGRyYXdzIHBvciBjYWRlbmENCiAgd2FybXVwID0gNTAwMCwgICAgIyBidXJuLWluDQogIGNvcmVzICA9IDQsDQogIHNlZWQgICA9IDQyLA0KICBzYW1wbGVfcHJpb3IgPSAieWVzIg0KKQ0KYGBgDQpgYGB7ciBiYXllc192MV9yZXN1bHR9DQpzdW1tYXJ5KHRheWxvcl9iYXllc192MV9icm1zKQ0KYGBgDQpMb3MgcmVzdWx0YWRvcyBiYXllc2lhbm9zIGNvbiBwcmlvcnMgZMOpYmlsZXMgc29uIG11eSBzaW1pbGFyZXMgYSBsb3MgZGUgT0xTOiBsb3MgY29lZmljaWVudGVzIGRlIGluZXJjaWEsIGluZmxhY2nDs24geSBvdXRwdXQgZ2FwIG1hbnRpZW5lbiBtYWduaXR1ZGVzIGNhc2kgaWTDqW50aWNhcyB5IGNvbnRpbsO6YW4gc2llbmRvIGNsYXJhbWVudGUgc2lnbmlmaWNhdGl2b3MuIExvcyBpbnRlcnZhbG9zIGFsIDk1JSByZWZsZWphbiBsYSBtaXNtYSBpbmZvcm1hY2nDs24gcXVlIGxvcyBpbnRlcnZhbG9zIGRlIGNvbmZpYW56YSBjbMOhc2ljb3MsIGluZGljYW5kbyBxdWUgbGFzIHByaW9ycyBubyBhbHRlcmFuIHN1c3RhbmNpYWxtZW50ZSBsYSBlc3RpbWFjacOzbi4gRW4gc8OtbnRlc2lzLCBlbCBtb2RlbG8gYmF5ZXNpYW5vIHJlcHJvZHVjZSBkZSBtYW5lcmEgY29uc2lzdGVudGUgbGEgZXN0cnVjdHVyYSBvYnRlbmlkYSBwb3IgT0xTLg0KDQojIyBSZWdyZXNpw7NuIEJheWVzaWFuYSAjMiAtIFByaW9ycyBGdWVydGVzDQpFbiBlc3RhIHNlZ3VuZGEgZXNwZWNpZmljYWNpw7NuIHNlIG1hbnRpZW5lIGxhIG1pc21hIGVzdHJ1Y3R1cmEgZGVsIG1vZGVsbywgcGVybyBzZSByZWVtcGxhemFuIGxhcyBwcmlvcnMgZMOpYmlsZXMgcG9yIHByaW9ycyBtdWNobyBtw6FzIGNvbmNlbnRyYWRhcywgYmFzYWRhcyBlbiBlc3RpbWFjaW9uZXMgZGVsIEJJUy4gRXN0byBwZXJtaXRlIGV2YWx1YXIgY3XDoW50byBpbmZsdXllbiBsYXMgY3JlZW5jaWFzIHByZXZpYXMgZW4gbG9zIGNvZWZpY2llbnRlcyBkZSBsYSBSZWdsYSBkZSBUYXlsb3IsIGZvcnphbmRvIGFsIG1vZGVsbyBhIGNvbWVuemFyIGRlc2RlIHZhbG9yZXMgbXV5IGVzcGVjw61maWNvcyBwYXJhIGxhIGluZXJjaWEgbW9uZXRhcmlhLCBsYSByZXNwdWVzdGEgYSBsYSBpbmZsYWNpw7NuIHkgbGEgcmVzcHVlc3RhIGFsIGNpY2xvLg0KDQpgYGB7ciBiYXllc192MiwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCnByaW9yc192MiA8LSBjKA0KICBwcmlvcihub3JtYWwoMCwgICAgNS4wKSwgY2xhc3MgPSAiSW50ZXJjZXB0IiksDQogIHByaW9yKG5vcm1hbCgwLjc0LCAwLjEwKSwgY2xhc3MgPSAiYiIsIGNvZWYgPSAiaV9sYWcxIiksDQogIHByaW9yKG5vcm1hbCgyLjExLCAwLjEwKSwgY2xhc3MgPSAiYiIsIGNvZWYgPSAicGlfZ2FwIiksDQogIHByaW9yKG5vcm1hbCgwLjI2LCAwLjA1KSwgY2xhc3MgPSAiYiIsIGNvZWYgPSAieV9nYXAiKSwNCiAgDQojIFByaW9yIGTDqWJpbCBwYXJhIHNpZ21hIChhbsOhbG9nbyBhIGludi1nYW1tYSBtdXkgcGxhbmEgZW4gc2lnbWFeMikNCiAgcHJpb3Ioc3R1ZGVudF90KDMsIDAsIDEwKSwgY2xhc3MgPSAic2lnbWEiKQ0KKQ0KDQpzZXQuc2VlZCg0MikNCg0KdGF5bG9yX2JheWVzX3YyX2JybXMgPC0gYnJtKA0KICBGRURGVU5EUyB+IGlfbGFnMSArIHBpX2dhcCArIHlfZ2FwLA0KICBkYXRhICAgPSBkZl9yZWdfc3ViLA0KICBmYW1pbHkgPSBnYXVzc2lhbigpLA0KICBwcmlvciAgPSBwcmlvcnNfdjIsDQogIA0KICBjaGFpbnMgPSA0LA0KICBpdGVyICAgPSAxNTAwMCwNCiAgd2FybXVwID0gNTAwMCwNCiAgY29yZXMgID0gNCwNCiAgc2VlZCAgID0gNDIsDQogIHNhbXBsZV9wcmlvciA9ICJ5ZXMiDQopDQpgYGANCmBgYHtyIGJheWVzX3YyX3Jlc3VsdH0NCnN1bW1hcnkodGF5bG9yX2JheWVzX3YyX2JybXMpDQpgYGANCkxvcyByZXN1bHRhZG9zIGNvbiBwcmlvcnMgZnVlcnRlcyBtdWVzdHJhbiBjb2VmaWNpZW50ZXMgY2xhcmFtZW50ZSBpbmZsdWVuY2lhZG9zIHBvciBsYSBpbmZvcm1hY2nDs24gcHJldmlhOiBsYSByZXNwdWVzdGEgYSBsYSBpbmZsYWNpw7NuIGF1bWVudGEgZGUgbWFuZXJhIG1hcmNhZGEgKOKJiCAxLjk1KSwgbWllbnRyYXMgcXVlIGxhIGluZXJjaWEgbW9uZXRhcmlhIHNlIHJlZHVjZSAo4omIIDAuNzkpLCBtb3Zpw6luZG9zZSBhbWJvcyBlbiBkaXJlY2Npw7NuIGEgbG9zIHZhbG9yZXMgZmlqYWRvcyBlbiBsYXMgcHJpb3JzLiBFbCBvdXRwdXQgZ2FwIHRhbWJpw6luIHByZXNlbnRhIHVuIGNvZWZpY2llbnRlIG1heW9yICjiiYggMC4yMikuIFRvZG9zIGxvcyBwYXLDoW1ldHJvcyByZXN1bHRhbiBlc3RhZMOtc3RpY2FtZW50ZSBzaWduaWZpY2F0aXZvcyByZWZsZWphbmRvIGxhIG1heW9yIHByZWNpc2nDs24gaW1wdWVzdGEgcG9yIGxhcyBwcmlvcnMuIEVuIGNvbmp1bnRvLCBlc3RhIHZlcnNpw7NuIGRlbCBtb2RlbG8gaWx1c3RyYSBjw7NtbyBwcmlvcnMgbcOhcyBjb25jZW50cmFkYXMgcHVlZGVuIG1vZGlmaWNhciBzdXN0YW5jaWFsbWVudGUgbGFzIGVzdGltYWNpb25lcy4NCg0KIyBBbsOhbGlzaXMgR3LDoWZpY28NCg0KIyMgMSkgRm9yZXN0IHBsb3QNCkVsIGdyw6FmaWNvIGNvbXBhcmEgbG9zIGNvZWZpY2llbnRlcyBlc3RpbWFkb3MgcG9yIE9MUyBjb24gbGFzIGRpc3RyaWJ1Y2lvbmVzIHBvc3RlcmlvcmVzIG9idGVuaWRhcyBiYWpvIGxvcyBtb2RlbG9zIGJheWVzaWFub3MgY29uIHByaW9ycyBkw6liaWxlcyB5IGZ1ZXJ0ZXMuIFNlIG9ic2VydmEgcXVlLCBtaWVudHJhcyBsYSB2ZXJzacOzbiBjb24gcHJpb3JzIGTDqWJpbGVzIHJlcHJvZHVjZSBjYXNpIGV4YWN0YW1lbnRlIGxvcyB2YWxvcmVzIGRlIE9MUywgbGFzIHByaW9ycyBmdWVydGVzIGRlc3BsYXphbiBsYXMgZGlzdHJpYnVjaW9uZXMgaGFjaWEgbG9zIHZhbG9yZXMgaW1wdWVzdG9zIHBvciBsYSBpbmZvcm1hY2nDs24gcHJldmlhLCBlc3BlY2lhbG1lbnRlIGVuIGxhIHJlc3B1ZXN0YSBhIGxhIGluZmxhY2nDs24uIEVzdG8gcGVybWl0ZSB2aXN1YWxpemFyIGRlIG1hbmVyYSBkaXJlY3RhIGPDs21vIGVsIHBlc28gZGUgbGFzIHByaW9ycyBhZmVjdGEgbGEgZXN0aW1hY2nDs24gZGUgY2FkYSBwYXLDoW1ldHJvLg0KYGBge3IgZm9yZXN0LCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyBpKSBDb2VmaWNpZW50ZXMgT0xTDQpvbHNfdGlkeSA8LSBicm9vbTo6dGlkeSh0YXlsb3Jfb2xzLCBjb25mLmludCA9IFRSVUUpICU+JQ0KICBmaWx0ZXIodGVybSAhPSAiKEludGVyY2VwdCkiKSAlPiUNCiAgbXV0YXRlKG1vZGVsID0gIk9MUyIpDQoNCiMgaWkpIENvZWZpY2llbnRlcyBCYXllczogZHJhd3MgZGUgYnJtcw0KYjFfZHJhd3MgPC0gdGF5bG9yX2JheWVzX3YxX2JybXMgJT4lDQogIHNwcmVhZF9kcmF3cyhiX2lfbGFnMSwgYl9waV9nYXAsIGJfeV9nYXApICU+JQ0KICBkcGx5cjo6c2VsZWN0KGJfaV9sYWcxLCBiX3BpX2dhcCwgYl95X2dhcCkgJT4lDQogIHBpdm90X2xvbmdlcihjb2xzID0gZXZlcnl0aGluZygpLA0KICAgICAgICAgICAgICAgbmFtZXNfdG8gPSAidGVybSIsDQogICAgICAgICAgICAgICB2YWx1ZXNfdG8gPSAidmFsdWUiKSAlPiUNCiAgbXV0YXRlKG1vZGVsID0gIk1vZGVsbyBjb24gcHJpb3JzIGTDqWJpbGVzIikNCg0KYjJfZHJhd3MgPC0gdGF5bG9yX2JheWVzX3YyX2JybXMgJT4lDQogIHNwcmVhZF9kcmF3cyhiX2lfbGFnMSwgYl9waV9nYXAsIGJfeV9nYXApICU+JQ0KICBkcGx5cjo6c2VsZWN0KGJfaV9sYWcxLCBiX3BpX2dhcCwgYl95X2dhcCkgJT4lDQogIHBpdm90X2xvbmdlcihjb2xzID0gZXZlcnl0aGluZygpLA0KICAgICAgICAgICAgICAgbmFtZXNfdG8gPSAidGVybSIsDQogICAgICAgICAgICAgICB2YWx1ZXNfdG8gPSAidmFsdWUiKSAlPiUNCiAgbXV0YXRlKG1vZGVsID0gIk1vZGVsbyBjb24gcHJpb3JzIGZ1ZXJ0ZXMiKQ0KDQpiYXllc19kcmF3cyA8LSBiaW5kX3Jvd3MoYjFfZHJhd3MsIGIyX2RyYXdzKSAlPiUNCiAgbXV0YXRlKHRlcm0gPSByZWNvZGUodGVybSwNCiAgICAgICAgICAgICAgICAgICAgICAgYl9pX2xhZzEgPSAiaV9sYWcxIChyaG8pIiwNCiAgICAgICAgICAgICAgICAgICAgICAgYl9waV9nYXAgPSAicGlfZ2FwIChwaGlfcGkpIiwNCiAgICAgICAgICAgICAgICAgICAgICAgYl95X2dhcCAgPSAieV9nYXAgKHBoaV95KSIpKQ0KDQpvbHNfdGlkeSA8LSBvbHNfdGlkeSAlPiUNCiAgbXV0YXRlKHRlcm0gPSByZWNvZGUodGVybSwNCiAgICAgICAgICAgICAgICAgICAgICAgaV9sYWcxID0gImlfbGFnMSAocmhvKSIsDQogICAgICAgICAgICAgICAgICAgICAgIHBpX2dhcCA9ICJwaV9nYXAgKHBoaV9waSkiLA0KICAgICAgICAgICAgICAgICAgICAgICB5X2dhcCAgPSAieV9nYXAgKHBoaV95KSIpKQ0KDQojIGlpaSkgR3LDoWZpY28gY29tYmluYWRvDQpnZ3Bsb3QoYmF5ZXNfZHJhd3MsIGFlcyh4ID0gdmFsdWUsIHkgPSB0ZXJtLCBmaWxsID0gbW9kZWwpKSArDQogIHN0YXRfaGFsZmV5ZShhbHBoYSA9IDAuNywgcG9pbnRfaW50ZXJ2YWwgPSBtZWRpYW5fcWksIC53aWR0aCA9IDAuOTUpICsNCiAgZ2VvbV9wb2ludChkYXRhID0gb2xzX3RpZHksIGFlcyh4ID0gZXN0aW1hdGUsIHkgPSB0ZXJtKSwNCiAgICAgICAgICAgICBpbmhlcml0LmFlcyA9IEZBTFNFLCBzaGFwZSA9IDIxLCBzaXplID0gMi4yLCBmaWxsID0gIndoaXRlIikgKw0KICBnZW9tX2Vycm9yYmFyaChkYXRhID0gb2xzX3RpZHksDQogICAgICAgICAgICAgICAgIGFlcyh4bWluID0gY29uZi5sb3csIHhtYXggPSBjb25mLmhpZ2gsIHkgPSB0ZXJtKSwNCiAgICAgICAgICAgICAgICAgaW5oZXJpdC5hZXMgPSBGQUxTRSwgaGVpZ2h0ID0gMC4xNSkgKw0KICBsYWJzKHggPSAiVmFsb3IgZGVsIGNvZWZpY2llbnRlIiwgeSA9IE5VTEwsDQogICAgICAgdGl0bGUgPSAiT0xTIHZzIEJheWVzIiwNCiAgICAgICBzdWJ0aXRsZSA9ICJEaXN0cmlidWNpb25lcyBwb3N0ZXJpb3JlcyB5IElDIE9MUyIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQpgYGANCg0KIyMgIDIpIFByaW9yIHZzIFBvc3RlcmlvciAocGFyYSAjMSB5ICMyKQ0KRWwgZ3LDoWZpY28gbXVlc3RyYSBjw7NtbyBzZSBjb21wYXJhbiBsYXMgZGlzdHJpYnVjaW9uZXMgcHJpb3IgeSBwb3N0ZXJpb3IgZW4gYW1ib3MgbW9kZWxvcy4gQ29uIHByaW9ycyBkw6liaWxlcywgbG9zIGRhdG9zIG1vZGlmaWNhbiBmdWVydGVtZW50ZSBsYSBkaXN0cmlidWNpw7NuIHBvc3Rlcmlvci4gQ29uIHByaW9ycyBmdWVydGVzLCBsYSBwb3N0ZXJpb3IgcGVybWFuZWNlIG11eSBjZXJjYSBkZSBsYSBwcmlvciwgaW5kaWNhbmRvIHF1ZSBsYSBpbmZvcm1hY2nDs24gcHJldmlhIHRpZW5lIG11Y2hvIG3DoXMgcGVzbyBlbiBsYSBlc3RpbWFjacOzbi4NCmBgYHtyIHByaW9yX3Bvc3QsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9IA0KcGFycyA8LSBjKCJiX2lfbGFnMSIsICJiX3BpX2dhcCIsICJiX3lfZ2FwIikNCg0KbWFrZV9wcmlvcl9wb3N0X2xvbmcgPC0gZnVuY3Rpb24oZml0LCBsYWJlbCl7DQogIHByaW9yX2RmIDwtIHByaW9yX2RyYXdzKGZpdCkgJT4lDQogICAgYXNfZHJhd3NfZGYoKSAlPiUNCiAgICBkcGx5cjo6c2VsZWN0KGFsbF9vZihwYXJzKSkgJT4lDQogICAgcGl2b3RfbG9uZ2VyKGV2ZXJ5dGhpbmcoKSwgbmFtZXNfdG8gPSAidGVybSIsIHZhbHVlc190byA9ICJ2YWx1ZSIpICU+JQ0KICAgIG11dGF0ZSh0eXBlID0gIlByaW9yIiwgbW9kZWwgPSBsYWJlbCkNCiAgDQogIHBvc3RfZGYgPC0gYXNfZHJhd3NfZGYoZml0KSAlPiUNCiAgICBkcGx5cjo6c2VsZWN0KGFsbF9vZihwYXJzKSkgJT4lDQogICAgcGl2b3RfbG9uZ2VyKGV2ZXJ5dGhpbmcoKSwgbmFtZXNfdG8gPSAidGVybSIsIHZhbHVlc190byA9ICJ2YWx1ZSIpICU+JQ0KICAgIG11dGF0ZSh0eXBlID0gIlBvc3RlcmlvciIsIG1vZGVsID0gbGFiZWwpDQogIA0KICBiaW5kX3Jvd3MocHJpb3JfZGYsIHBvc3RfZGYpDQp9DQoNCmRmX3YxIDwtIG1ha2VfcHJpb3JfcG9zdF9sb25nKHRheWxvcl9iYXllc192MV9icm1zLCAiUHJpb3JzIGTDqWJpbGVzIikNCmRmX3YyIDwtIG1ha2VfcHJpb3JfcG9zdF9sb25nKHRheWxvcl9iYXllc192Ml9icm1zLCAiUHJpb3JzIGZ1ZXJ0ZXMiKQ0KDQpkZl9hbGwgPC0gYmluZF9yb3dzKGRmX3YxLCBkZl92MikgJT4lDQogIG11dGF0ZSgNCiAgICB0ZXJtID0gcmVjb2RlKHRlcm0sDQogICAgICAgICAgICAgICAgICBiX2lfbGFnMSA9ICJpX2xhZzEgKHJobykiLA0KICAgICAgICAgICAgICAgICAgYl9waV9nYXAgPSAicGlfZ2FwIChwaGlfcGkpIiwNCiAgICAgICAgICAgICAgICAgIGJfeV9nYXAgID0gInlfZ2FwIChwaGlfeSkiKSwNCiAgICB0ZXJtID0gZmFjdG9yKHRlcm0sIGxldmVscyA9IGMoImlfbGFnMSAocmhvKSIsICJwaV9nYXAgKHBoaV9waSkiLCAieV9nYXAgKHBoaV95KSIpKQ0KICApDQoNCmdncGxvdChkZl9hbGwsIGFlcyh4ID0gdmFsdWUsIHkgPSB0ZXJtLCBmaWxsID0gdHlwZSkpICsNCiAgc3RhdF9oYWxmZXllKGFscGhhID0gMC42LCBwb3NpdGlvbiA9ICJpZGVudGl0eSIsDQogICAgICAgICAgICAgICBwb2ludF9pbnRlcnZhbCA9IG1lZGlhbl9xaSwgLndpZHRoID0gMC45NSkgKw0KICBmYWNldF93cmFwKH5tb2RlbCkgKw0KICBjb29yZF9jYXJ0ZXNpYW4oeGxpbSA9IGMoLTEsIDQpKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiUHJpb3IgdnMgUG9zdGVyaW9yIHBvciBtb2RlbG8iLA0KICAgIHN1YnRpdGxlID0gIkNvbXBhcmFjacOzbiB2aXN1YWwgcGFyYSBwcmlvcnMgZMOpYmlsZXMgeSBmdWVydGVzIiwNCiAgICB4ID0gIlZhbG9yIGRlbCBjb2VmaWNpZW50ZSIsIHkgPSBOVUxMDQogICkgKw0KICB0aGVtZV9taW5pbWFsKCkNCmBgYA0KDQojIyAzKSBDb21wYXJhY2nDs24gUHJlZGljdGl2YTogRml0dGVkIHZzIGFjdHVhbA0KRWwgZ3LDoWZpY28gY29tcGFyYSBsYSB0YXNhIG9ic2VydmFkYSBjb24gbGFzIHByZWRpY2Npb25lcyBvYnRlbmlkYXMgcG9yIE9MUyB5IHBvciBsb3MgbW9kZWxvcyBiYXllc2lhbm9zIGNvbiBwcmlvcnMgZMOpYmlsZXMgeSBmdWVydGVzLiBFbiBhbWJvcyBjYXNvcywgbGFzIHByZWRpY2Npb25lcyBiYXllc2lhbmFzIHNpZ3VlbiBtdXkgZGUgY2VyY2EgbGEgdHJheWVjdG9yaWEgaGlzdMOzcmljYSBkZSBsYSB0YXNhIGRlIGZvbmRvcyBmZWRlcmFsZXMsIHkgbGFzIGJhbmRhcyBjcmXDrWJsZXMgKDUwJSB5IDk1JSkgc29uIGVzdHJlY2hhcywgaW5kaWNhbmRvIGJ1ZW5hIHByZWNpc2nDs24gZGVsIG1vZGVsby4gTGFzIHByaW9ycyBmdWVydGVzIHByb2R1Y2VuIGludGVydmFsb3MgbGlnZXJhbWVudGUgbcOhcyBjb25jZW50cmFkb3MsIHJlZmxlamFuZG8gbWF5b3IgcGVzbyBkZSBsYSBpbmZvcm1hY2nDs24gcHJldmlhLg0KYGBge3IgcHJlZGljdCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0gDQpkZl9wbG90IDwtIGRmX3JlZ19zdWIgJT4lDQogIG11dGF0ZShmaXRfb2xzID0gcHJlZGljdCh0YXlsb3Jfb2xzLCBuZXdkYXRhID0gZGZfcmVnX3N1YikpDQoNCnByZWRfdjEgPC0gZGZfcmVnX3N1YiAlPiUNCiAgYWRkX2VwcmVkX2RyYXdzKHRheWxvcl9iYXllc192MV9icm1zLCBuZHJhd3MgPSAyMDAwKQ0KDQpwcmVkX3YyIDwtIGRmX3JlZ19zdWIgJT4lDQogIGFkZF9lcHJlZF9kcmF3cyh0YXlsb3JfYmF5ZXNfdjJfYnJtcywgbmRyYXdzID0gMjAwMCkNCg0Kc3VtbV9wcmVkIDwtIGZ1bmN0aW9uKHByZWRfZGYsIGxhYmVsKXsNCiAgcHJlZF9kZiAlPiUNCiAgICBncm91cF9ieShzYXNkYXRlKSAlPiUNCiAgICBtZWRpYW5fcWkoLmVwcmVkLCAud2lkdGggPSBjKDAuNSwgMC45NSkpICU+JQ0KICAgIG11dGF0ZShtb2RlbCA9IGxhYmVsKQ0KfQ0KDQpwMSA8LSBzdW1tX3ByZWQocHJlZF92MSwgIkJheWVzIHByaW9ycyBkw6liaWxlcyIpDQpwMiA8LSBzdW1tX3ByZWQocHJlZF92MiwgIkJheWVzIHByaW9ycyBmdWVydGVzIikNCg0KcHJlZF9iYW5kcyA8LSBiaW5kX3Jvd3MocDEsIHAyKQ0KDQpnZ3Bsb3QoZGZfcGxvdCwgYWVzKHggPSBzYXNkYXRlLCB5ID0gRkVERlVORFMpKSArDQogIGdlb21fbGluZShjb2xvciA9ICJibGFjayIpICsNCiAgZ2VvbV9saW5lKGFlcyh5ID0gZml0X29scyksIGxpbmV0eXBlID0gImRhc2hlZCIpICsNCiAgc3RhdF9saW5lcmliYm9uKGRhdGEgPSBwcmVkX2JhbmRzLA0KICAgICAgICAgICAgICAgICAgYWVzKHkgPSAuZXByZWQsIHltaW4gPSAubG93ZXIsIHltYXggPSAudXBwZXIsIGZpbGwgPSBtb2RlbCksDQogICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMjUpICsNCiAgZmFjZXRfd3JhcCh+bW9kZWwsIG5jb2wgPSAxKSArDQogIGxhYnModGl0bGUgPSAiUHJlZGljY2nDs246IE9MUyB2cyBCYXllcyIsDQogICAgICAgc3VidGl0bGUgPSAiQmFuZGFzIGNyZcOtYmxlcyA1MCUgeSA5NSUiLA0KICAgICAgIHkgPSAiRkVERlVORFMiLCB4ID0gTlVMTCkgKw0KICB0aGVtZV9taW5pbWFsKCkNCmBgYA0KDQojIyA0KSBEaXN0cmlidWNpb24gZGUgcmVhY2Npw7NuIGEgaW5mbGFjacOzbg0KTGEgZmlndXJhIG11ZXN0cmEgbGEgZGlzdHJpYnVjacOzbiBwb3N0ZXJpb3IgZGVsIHBhcsOhbWV0cm8gcXVlIG1pZGUgbGEgcmVzcHVlc3RhIGRlIGxhIHRhc2EgZGUgaW50ZXLDqXMgYSBsYSBpbmZsYWNpw7NuICjPlc+AKSBiYWpvIGFtYm9zIGNvbmp1bnRvcyBkZSBwcmlvcnMuIENvbiBwcmlvcnMgZMOpYmlsZXMsIGxhIGRpc3RyaWJ1Y2nDs24gZXMgbcOhcyBkaXNwZXJzYSB5IGNlbnRyYWRhIGFscmVkZWRvciBkZSB2YWxvcmVzIGNlcmNhbm9zIGEgMSwgbWllbnRyYXMgcXVlIGNvbiBwcmlvcnMgZnVlcnRlcyBzZSBjb25jZW50cmEgZW4gdG9ybm8gYWwgYmVuY2htYXJrIGRlIDIuMTEgcHJvcHVlc3RvIHBvciBlbCBCSVMgKGzDrW5lYSBwdW50ZWFkYSkuIEVzdG8gaWx1c3RyYSBjw7NtbyBsYSBpbmZvcm1hY2nDs24gcHJldmlhIGluZmx1eWUgZW4gbGEgbWFnbml0dWQgZXN0aW1hZGEgZGUgbGEgcmVhY2Npw7NuIGRlIHBvbMOtdGljYSBtb25ldGFyaWEuDQpgYGB7ciBpbmYsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9IA0KYjFfcGhpX3BpIDwtIGFzX2RyYXdzX2RmKHRheWxvcl9iYXllc192MV9icm1zKSRiX3BpX2dhcA0KYjJfcGhpX3BpIDwtIGFzX2RyYXdzX2RmKHRheWxvcl9iYXllc192Ml9icm1zKSRiX3BpX2dhcA0KDQpkZl9waGkgPC0gdGliYmxlKA0KICB2YWx1ZSA9IGMoYjFfcGhpX3BpLCBiMl9waGlfcGkpLA0KICBtb2RlbCA9IHJlcChjKCJQcmlvcnMgZMOpYmlsZXMiLCJQcmlvcnMgZnVlcnRlcyIpLA0KICAgICAgICAgICAgICBjKGxlbmd0aChiMV9waGlfcGkpLCBsZW5ndGgoYjJfcGhpX3BpKSkpDQopDQoNCmdncGxvdChkZl9waGksIGFlcyh4ID0gdmFsdWUsIGZpbGwgPSBtb2RlbCkpICsNCiAgZ2VvbV9kZW5zaXR5KGFscGhhID0gMC41KSArDQogIGdlb21fdmxpbmUoDQogICAgeGludGVyY2VwdCA9IDIuMTEsDQogICAgbGluZXR5cGUgPSAiZG90dGVkIiwNCiAgICBsaW5ld2lkdGggPSAxLjIsDQogICAgY29sb3IgPSAiYmxhY2siLA0KICAgIGFscGhhID0gMC45DQogICkgKw0KICBsYWJzKHRpdGxlID0gIlJlc3B1ZXN0YSBhIGluZmxhY2nDs24gKHBoaV9waSkiLA0KICAgICAgIHN1YnRpdGxlID0gIkzDrW5lYSBwdW50ZWFkYSA9IGJlbmNobWFyayBCSVMiLA0KICAgICAgIHggPSBleHByZXNzaW9uKHBoaVtwaV0pLCB5ID0gIkRlbnNpZGFkIikgKw0KICB0aGVtZV9taW5pbWFsKCkNCmBgYA0KDQojIyA1KSBTdGFja2VkIFBQQw0KTG9zIGdyw6FmaWNvcyBQUEMgcGVybWl0ZW4gZXZhbHVhciBzaSBsb3MgbW9kZWxvcyBiYXllc2lhbm9zIHB1ZWRlbiByZXByb2R1Y2lyIGxhIGRpc3RyaWJ1Y2nDs24gb2JzZXJ2YWRhIGRlIGxhIHRhc2EgZGUgaW50ZXLDqXMuIFRhbnRvIGVsIG1vZGVsbyBjb24gcHJpb3JzIGTDqWJpbGVzIGNvbW8gZWwgZGUgcHJpb3JzIGZ1ZXJ0ZXMgZ2VuZXJhbiBkaXN0cmlidWNpb25lcyBzaW11bGFkYXMgY29oZXJlbnRlcyBjb24gbG9zIGRhdG9zIHJlYWxlcywgbG8gcXVlIGluZGljYSB1biBhanVzdGUgYWRlY3VhZG8uDQpgYGB7ciBwcGMsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9IA0KcHBfY2hlY2sodGF5bG9yX2JheWVzX3YxX2JybXMsDQogICAgICAgICB0eXBlID0gImRlbnNfb3ZlcmxheSIsDQogICAgICAgICBuZHJhd3MgPSA1MCkgKw0KICBnZ3RpdGxlKCJQUEMgLSBQcmlvcnMgRMOpYmlsZXMiKSArDQogIGxhYnMoeCA9ICJGRURGVU5EUyIsIHkgPSAiRGVuc2lkYWQiKSArDQogIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBleHBhbnNpb24obXVsdCA9IGMoMCwgMC4wNSkpKSArDQogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTIpDQoNCnBwX2NoZWNrKHRheWxvcl9iYXllc192Ml9icm1zLA0KICAgICAgICAgdHlwZSA9ICJkZW5zX292ZXJsYXkiLA0KICAgICAgICAgbmRyYXdzID0gNTApICsNCiAgZ2d0aXRsZSgiUFBDIC0gUHJpb3JzIEZ1ZXJ0ZXMiKSArDQogIGxhYnMoeCA9ICJGRURGVU5EUyIsIHkgPSAiRGVuc2lkYWQiKSArDQogIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBleHBhbnNpb24obXVsdCA9IGMoMCwgMC4wNSkpKSArDQogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTIpDQpgYGANCg0KIyBCYXllc2lhbiBMYXNzbw0KDQpFbiBlc3RhIHNlY2Npw7NuIHNlIGV4dGllbmRlIGxhIGVzdGltYWNpw7NuIGRlIGxhIFJlZ2xhIGRlIFRheWxvciBpbmNvcnBvcmFuZG8gdW4gY29uanVudG8gZGUgdmFyaWFibGVzIG1hY3JvZWNvbsOzbWljYXMgYWRpY2lvbmFsZXMgKGNvbnRyb2xlcykuIFBhcmEgZXZpdGFyIHNvYnJlYWp1c3RlIHkgcGVybWl0aXIgcXVlIGVsIHByb3BpbyBtb2RlbG8gZGV0ZXJtaW5lIGN1w6FsZXMgZGUgZXN0b3MgY29udHJvbGVzIHNvbiByZWFsbWVudGUgcmVsZXZhbnRlcywgc2UgdXRpbGl6YSB1biBlbmZvcXVlIGJheWVzaWFubyBjb24gdW4gcHJpb3IgdGlwbyBMQVNTTyAoZGlzdHJpYnVjacOzbiBMYXBsYWNlKSwgcXVlIGluZHVjZSBzaHJpbmthZ2Ugc29icmUgdG9kb3MgbG9zIGNvZWZpY2llbnRlcyBhZGljaW9uYWxlcy4NCkxvcyBjb2VmaWNpZW50ZXMgY2VudHJhbGVzIGRlIGxhIFJlZ2xhIGRlIFRheWxvciDigJRpbmVyY2lhLCBicmVjaGEgZGUgaW5mbGFjacOzbiB5IG91dHB1dCBnYXDigJQgc2UgbWFudGllbmVuIGNvbiBwcmlvcnMgaW5mb3JtYXRpdm9zIGZ1ZXJ0ZXMgYXNlZ3VyYW5kbyBxdWUgTEFTU08gYWN0w7plIMO6bmljYW1lbnRlIHNvYnJlIGxvcyBjb250cm9sZXMuIEVzdGUgZW5mb3F1ZSBwZXJtaXRlIGV2YWx1YXIgc2ltdWx0w6FuZWFtZW50ZSBsYSByb2J1c3RleiBkZSBsYSByZWdsYSB5IGVsIGFwb3J0ZSBtYXJnaW5hbCBkZSB2YXJpYWJsZXMgbWFjcm9lY29uw7NtaWNhcyBhZGljaW9uYWxlcy4NCkxvcyBjb250cm9sZXMgcXVlIGVzdGFyZW1vcyB1c2FuZG8gc29uIGxvcyBzaWd1aWVudGVzOg0KDQotICoqVENVKio6IENhcGFjaXR5IFV0aWxpemF0aW9uOiBUb3RhbCBJbmR1c3RyeSAoUGVyY2VudCBvZiBDYXBhY2l0eSkNCi0gKipVU0dPVlQqKjogQWxsIEVtcGxveWVlczogR292ZXJubWVudCAoVGhvdXNhbmRzIG9mIFBlcnNvbnMpDQotICoqVU5SQVRFKio6IENpdmlsaWFuIFVuZW1wbG95bWVudCBSYXRlIChQZXJjZW50KQ0KLSAqKkRHRFNSRzNRMDg2U0JFQSoqOiBQZXJzb25hbCBjb25zdW1wdGlvbiBleHBlbmRpdHVyZXM6IEdvb2RzIChjaGFpbi10eXBlIHByaWNlIGluZGV4KQ0KLSAqKkdTMTBUQjNNeCoqOiAxMC1ZZWFyIFRyZWFzdXJ5IENvbnN0YW50IE1hdHVyaXR5IE1pbnVzIDMtTW9udGggVHJlYXN1cnkgQmlsbCwgc2Vjb25kYXJ5IG1hcmtldCAoUGVyY2VudCkNCi0gKipDUEYzTVRCM014Kio6IDMtTW9udGggQ29tbWVyY2lhbCBQYXBlciBNaW51cyAzLU1vbnRoIFRyZWFzdXJ5IEJpbGwsIHNlY29uZGFyeSBtYXJrZXQgKFBlcmNlbnQpDQotICoqQk9HTUJBU0VSRUFMeCoqOiBTdC4gTG91aXMgQWRqdXN0ZWQgTW9uZXRhcnkgQmFzZSAoQmlsbGlvbnMgb2YgMTk4Mi04NCBEb2xsYXJzKSwgZGVmbGF0ZWQgYnkgQ1BJDQoNCg0KYGBge3IgY29udHJvbHMsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIHJlc3VsdHM9J2hpZGUnfSANCmNvbnRyb2xzIDwtIGMoIlRDVSIsIlVTR09WVCIsIlVOUkFURSIsIkRHRFNSRzNRMDg2U0JFQSIsDQogICAgICAgICAgICAgICAgICAiR1MxMFRCM014IiwiQ1BGM01UQjNNeCIsIkJPR01CQVNFUkVBTHgiKQ0KDQojIEVzdGFuZGFyaXphbW9zIHZhcmlhYmxlcyBkZSBjb250cm9sICANCmRmX3JlZ19zdWIgPC0gZGZfcmVnX3N1YiAlPiUNCiBtdXRhdGUoYWNyb3NzKGFsbF9vZihjb250cm9scyksIH4gYXMubnVtZXJpYyhzY2FsZSgueCkpKSkNCg0KIyBGw7NybXVsYSAgICANCmZvcm1fdjMgPC0gYmYoIEZFREZVTkRTIH4gaV9sYWcxICsgcGlfZ2FwICsgeV9nYXAgKyBUQ1UgKyBVU0dPVlQgKyBVTlJBVEUgKyBER0RTUkczUTA4NlNCRUEgKyBHUzEwVEIzTXggKyBDUEYzTVRCM014ICsgQk9HTUJBU0VSRUFMeCApDQoNCnByaW9yc192MyA8LSBjKA0KICAjIEludGVyY2VwdG8NCiAgcHJpb3Iobm9ybWFsKDAsIDUuMCksIGNsYXNzID0gIkludGVyY2VwdCIpLA0KICANCiAgIyBMQVNTTyBnZW5lcmFsIHBhcmEgdG9kb3MgbG9zIGJldGFzIC0gZXF1aXZhbGUgYSAxL2xhbWJkYSwgYXPDrSBxdWUgc2kgLT4wIG1heW9yIGVzIGxhIHBlbmFsaXphY2nDs24gKHNocmlua2FnZSkNCiAgcHJpb3IoZG91YmxlX2V4cG9uZW50aWFsKDAsIDAuMiksIGNsYXNzID0gImIiKSwNCiAgDQogICMgTsO6Y2xlbyBCSVMgY29uIHByaW9ycyBub3JtYWxlcyBmdWVydGVzDQogIHByaW9yKG5vcm1hbCgwLjc0LCAwLjEwKSwgY2xhc3MgPSAiYiIsIGNvZWYgPSAiaV9sYWcxIiksDQogIHByaW9yKG5vcm1hbCgyLjExLCAwLjEwKSwgY2xhc3MgPSAiYiIsIGNvZWYgPSAicGlfZ2FwIiksDQogIHByaW9yKG5vcm1hbCgwLjI2LCAwLjA1KSwgY2xhc3MgPSAiYiIsIGNvZWYgPSAieV9nYXAiKSwNCiAgDQogICMgU2lnbWEgZMOpYmlsDQogIHByaW9yKHN0dWRlbnRfdCgzLCAwLCAxMCksIGNsYXNzID0gInNpZ21hIikNCikNCg0KIyBBanVzdGUNCnNldC5zZWVkKDQyKQ0KDQp0YXlsb3JfYmF5ZXNfdjNfYnJtcyA8LSBicm0oDQogIGZvcm11bGEgPSBmb3JtX3YzLA0KICBkYXRhICAgID0gZGZfcmVnX3N1YiwNCiAgZmFtaWx5ICA9IGdhdXNzaWFuKCksDQogIHByaW9yICAgPSBwcmlvcnNfdjMsDQogIGNoYWlucyA9IDQsDQogIGl0ZXIgICA9IDE1MDAwLA0KICB3YXJtdXAgPSA1MDAwLA0KICBjb3JlcyAgPSA0LA0KICBzZWVkICAgPSA0MiwNCiAgc2FtcGxlX3ByaW9yID0gInllcyINCikNCmBgYA0KDQpgYGB7ciBjb250cm9sc19zdW1tLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfSANCnN1bW1hcnkodGF5bG9yX2JheWVzX3YzX2JybXMpDQpgYGANCkxhIGVzdGltYWNpw7NuIGJheWVzaWFuYSBjb24gcHJpb3IgTEFTU08gbXVlc3RyYSBxdWUgbG9zIGNvZWZpY2llbnRlcyBwcmluY2lwYWxlcyBkZSBsYSBSZWdsYSBkZSBUYXlsb3IgKGluZXJjaWEsIGJyZWNoYSBkZSBpbmZsYWNpw7NuIHkgb3V0cHV0IGdhcCkgc2UgbWFudGllbmVuIHNpZ25pZmljYXRpdm9zIHkgY29uIG1hZ25pdHVkZXMgY29uc2lzdGVudGVzIGNvbiBsYXMgdmVyc2lvbmVzIGFudGVyaW9yZXMuIEVuIGNhbWJpbywgbGEgbWF5b3LDrWEgZGUgbGFzIHZhcmlhYmxlcyBkZSBjb250cm9sIHByZXNlbnRhbiBkaXN0cmlidWNpb25lcyBwb3N0ZXJpb3JlcyBjZW50cmFkYXMgY2VyY2EgZGUgY2VybyB5IGNvbiBpbnRlcnZhbG9zIGFtcGxpb3MsIGluZGljYW5kbyBxdWUgZWwgc2hyaW5rYWdlIHBlbmFsaXphIGZ1ZXJ0ZW1lbnRlIHN1IGFwb3J0ZSBtYXJnaW5hbC4gU29sbyBHUzEwVEIzTXggbXVlc3RyYSBldmlkZW5jaWEgbW9kZXJhZGEgZGUgZWZlY3RvLiBFbiBjb25qdW50bywgZWwgbW9kZWxvIGNvbmZpcm1hIHF1ZSBsYSBkaW7DoW1pY2EgZGUgdGFzYXMgZXN0w6EgZXhwbGljYWRhIGNhc2kgcG9yIGNvbXBsZXRvIHBvciBsb3MgY29tcG9uZW50ZXMgY2VudHJhbGVzIGRlIGxhIHJlZ2xhLg0KDQojIyBWaXN1YWxpemFjacOzbiBkZSBSZXN1bHRhZG9zICAgIA0KDQpgYGB7ciBjb250cm9sc192aXosIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9IA0KIyBWaXN1YWxpemFjaW9uIGRlIGNvbnRyb2xlcw0KY29udHJvbHNfYiA8LSBjKCJiX1RDVSIsImJfVVNHT1ZUIiwiYl9VTlJBVEUiLCJiX0RHRFNSRzNRMDg2U0JFQSIsDQogICAgICAgICAgICAgICAgImJfR1MxMFRCM014IiwiYl9DUEYzTVRCM014IiwiYl9CT0dNQkFTRVJFQUx4IikNCg0KYXNfZHJhd3NfZGYodGF5bG9yX2JheWVzX3YzX2JybXMpICU+JQ0KICBkcGx5cjo6c2VsZWN0KGFsbF9vZihjb250cm9sc19iKSkgJT4lDQogIHBpdm90X2xvbmdlcihldmVyeXRoaW5nKCksIG5hbWVzX3RvPSJ0ZXJtIiwgdmFsdWVzX3RvPSJ2YWx1ZSIpICU+JQ0KICBnZ3Bsb3QoYWVzKHg9dmFsdWUsIHk9dGVybSkpICsNCiAgc3RhdF9oYWxmZXllKC53aWR0aCA9IDAuOTUpICsNCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0PTAsIGxpbmV0eXBlPSJkYXNoZWQiKSArDQogIGxhYnModGl0bGU9IkNvbnRyb2xlcyBjb24gcHJpb3IgTEFTU086IHBvc3RlcmlvciIsDQogICAgICAgc3VidGl0bGU9IkxvcyBxdWUgcXVlZGFuIGNvbmNlbnRyYWRvcyBlbiAwIG5vIGFwb3J0YW4iLA0KICAgICAgIHg9IkNvZWZpY2llbnRlIiwgeT1OVUxMKSArDQogIHRoZW1lX21pbmltYWwoKQ0KYGBgDQoNCkVzdGUgZ3LDoWZpY28gbXVlc3RyYSBsYSBkaXN0cmlidWNpw7NuIHBvc3RlcmlvciBkZSBsb3MgY29lZmljaWVudGVzIGFzb2NpYWRvcyBhIGxhcyB2YXJpYWJsZXMgZGUgY29udHJvbCBiYWpvIGVsIHByaW9yIExBU1NPLg0KTGFzIGRpc3RyaWJ1Y2lvbmVzIHF1ZSBxdWVkYW4gY29uY2VudHJhZGFzIGFscmVkZWRvciBkZSBjZXJvIGluZGljYW4gcXVlLCBkYWRvIGVsIHNocmlua2FnZSBhcGxpY2FkbywgZXNhcyB2YXJpYWJsZXMgbm8gYXBvcnRhbiBpbmZvcm1hY2nDs24gcmVsZXZhbnRlLg0KDQpgYGB7ciBsYW1iZGFzLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCByZXN1bHRzPSdoaWRlJ30gDQoNCiMgQ29tcGFyYWNpw7NuIGRlIExhbWJkYXMNCg0KIyBncmlsbGEgZGUgc2NhbGVzIChiKTogZGUgZMOpYmlsIGEgZnVlcnRlDQpiX2dyaWQgPC0gYygxLjAsIDAuNywgMC41LCAwLjMsIDAuMiwgMC4xNSwgMC4xLCAwLjA3LCAwLjA1LCAwLjAyNSkNCg0KIyBGdW5jaW9uIHF1ZSBhcm1hIHByaW9ycyBjb24gY2FkYSBiDQptYWtlX3ByaW9yc192MyA8LSBmdW5jdGlvbihiX3NjYWxlKXsNCiAgDQogIGxhcGxhY2Vfc3RyIDwtIHBhc3RlMCgiZG91YmxlX2V4cG9uZW50aWFsKDAsICIsIGJfc2NhbGUsICIpIikNCiAgDQogIGMoDQogICAgIyBJbnRlcmNlcHRvDQogICAgc2V0X3ByaW9yKCJub3JtYWwoMCwgNS4wKSIsIGNsYXNzID0gIkludGVyY2VwdCIpLA0KICAgIA0KICAgICMgTEFTU08gZ2VuZXJhbCBwYXJhIHRvZG9zIGxvcyBjb2VmaWNpZW50ZXMgYg0KICAgIHNldF9wcmlvcihsYXBsYWNlX3N0ciwgY2xhc3MgPSAiYiIpLA0KICAgIA0KICAgICMgU29icmVzY3JpYm8gbsO6Y2xlbyBCSVMgY29uIG5vcm1hbGVzIGZ1ZXJ0ZXMNCiAgICBzZXRfcHJpb3IoIm5vcm1hbCgwLjc0LCAwLjEwKSIsIGNsYXNzID0gImIiLCBjb2VmID0gImlfbGFnMSIpLA0KICAgIHNldF9wcmlvcigibm9ybWFsKDIuMTEsIDAuMTApIiwgY2xhc3MgPSAiYiIsIGNvZWYgPSAicGlfZ2FwIiksDQogICAgc2V0X3ByaW9yKCJub3JtYWwoMC4yNiwgMC4wNSkiLCBjbGFzcyA9ICJiIiwgY29lZiA9ICJ5X2dhcCIpLA0KICAgIA0KICAgICMgc2lnbWEgZMOpYmlsDQogICAgc2V0X3ByaW9yKCJzdHVkZW50X3QoMywgMCwgMTApIiwgY2xhc3MgPSAic2lnbWEiKQ0KICApDQp9DQoNCg0KIyBSZWVzdGltYXIgbW9kZWxvcyBwYXJhIGNhZGEgYg0KDQpmaXRzX3YzIDwtIG1hcChiX2dyaWQsIH4gYnJtKA0KICBmb3JtdWxhID0gZm9ybV92MywNCiAgZGF0YSAgICA9IGRmX3JlZ19zdWIsDQogIGZhbWlseSAgPSBnYXVzc2lhbigpLA0KICBwcmlvciAgID0gbWFrZV9wcmlvcnNfdjMoLngpLA0KICBjaGFpbnMgID0gNCwNCiAgaXRlciAgICA9IDQwMDAsDQogIHdhcm11cCAgPSAxMDAwLA0KICBjb3JlcyAgID0gNCwNCiAgc2VlZCAgICA9IDQyLA0KICByZWZyZXNoID0gMCANCikpDQoNCg0KbmFtZXMoZml0c192MykgPC0gcGFzdGUwKCJiXyIsIGJfZ3JpZCkNCg0KIyBFeHRyYWVyIGNvZmllY2llbnRlcyBkZSBjb250cm9sZXMgeSBjb25zdHJ1aXIgZWwgcGF0aA0KY29yZV92YXJzIDwtIGMoImlfbGFnMSIsICJwaV9nYXAiLCAieV9nYXAiKQ0KY29yZV9iIDwtIHBhc3RlMCgiYl8iLCBjb3JlX3ZhcnMpDQoNCiMgb2J0aWVuZSBub21icmVzIGJfIHJlYWxlcyBkZXNkZSBjdWFscXVpZXIgZml0IGJybXMNCmdldF9jb250cm9sc19iIDwtIGZ1bmN0aW9uKGZpdCkgew0KICBiX25hbWVzIDwtIGdyZXAoIl5iXyIsIHBvc3Rlcmlvcjo6dmFyaWFibGVzKGFzX2RyYXdzX2RmKGZpdCkpLCB2YWx1ZSA9IFRSVUUpDQogIHNldGRpZmYoYl9uYW1lcywgY29yZV9iKQ0KfQ0KDQpjb250cm9sc19iIDwtIGdldF9jb250cm9sc19iKGZpdHNfdjNbWzFdXSkgICMgdXNhciBlbCBwcmltZXIgZml0IGNvbW8gcmVmZXJlbmNpYQ0KY29udHJvbHNfYg0KDQojIGZ1bmNpw7NuIHBhcmEgZXh0cmFlciBlbCBjb2VmaWNpZW50ZSAibW9kYSIgZGVsIHZlY3Rvcg0KZ2V0X21vZGUgPC0gZnVuY3Rpb24oeCkgew0KICBkIDwtIGRlbnNpdHkoeCkNCiAgZCR4W3doaWNoLm1heChkJHkpXQ0KfQ0KDQoNCnBhdGhzX2RmX21hcCA8LSBtYXAyX2RmcihmaXRzX3YzLCBiX2dyaWQsIH4gew0KICAjIGV4dHJhZXIgZHJhd3MgZGUgbG9zIGNvZWZpY2llbnRlcyBkZSBjb250cm9sZXMNCiAgZHJhd3MgPC0gYXNfZHJhd3NfZGYoLngpICU+JQ0KICAgIGRwbHlyOjpzZWxlY3QoYWxsX29mKGNvbnRyb2xzX2IpKSAlPiUNCiAgICBwaXZvdF9sb25nZXIoZXZlcnl0aGluZygpLCBuYW1lc190bz0idGVybSIsIHZhbHVlc190bz0idmFsdWUiKSAlPiUNCiAgICAjIGV4Y2x1aXIgaW50ZXJjZXB0bw0KICAgIGZpbHRlcih0ZXJtICE9ICJiX0ludGVyY2VwdCIpICU+JQ0KICAgIGdyb3VwX2J5KHRlcm0pICU+JQ0KICAgIHN1bW1hcmlzZSgNCiAgICAgIG1hcCA9IGdldF9tb2RlKHZhbHVlKSwNCiAgICAgIC5ncm91cHM9ImRyb3AiDQogICAgKQ0KICANCiAgZHJhd3MgJT4lDQogICAgbXV0YXRlKA0KICAgICAgYl9zY2FsZSA9IC55LA0KICAgICAgbG9nX2xhbWJkYSA9IGxvZygxLy55KSAgICMgbGFtYmRhIGNsw6FzaWNhID0gMS9iDQogICAgKQ0KfSkNCg0KIyBHcmFmaWNhciBjb2VmaWNpZW50IHBhdGggY29uIE1BUCAoc2luIGludGVyY2VwdG8pDQpnZ3Bsb3QocGF0aHNfZGZfbWFwLCBhZXMoeCA9IGxvZ19sYW1iZGEsIHkgPSBtYXAsIGNvbG9yID0gdGVybSkpICsNCiAgZ2VvbV9saW5lKGxpbmV3aWR0aCA9IDAuOSkgKw0KICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiQ29lZmljaWVudCBwYXRocyBwYXJhIGNvbnRyb2xlcyAodjMpIiwNCiAgICBzdWJ0aXRsZSA9ICJBIG1heW9yIGxvZyhsYW1iZGEpID0gbWF5b3Igc2hyaW5rYWdlIChiIG3DoXMgY2hpY28pIiwNCiAgICB4ID0gImxvZyhsYW1iZGEpICBbbGFtYmRhID0gMSAvIGJfc2NhbGVdIiwNCiAgICB5ID0gIk1vZGEgcG9zdGVyaW9yIGRlbCBjb2VmaWNpZW50ZSINCiAgKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkNCg0KYGBgDQoNCkVuIGVzdGUgY2Fzbywgc2UgcHVlZGUgdmVyIGPDs21vIGNhbWJpYW4gbG9zIGNvZWZpY2llbnRlcyBkZSBsYXMgdmFyaWFibGVzIGRlIGNvbnRyb2wgYSBtZWRpZGEgcXVlIGF1bWVudGEgbGEgcGVuYWxpemFjacOzbiBMQVNTTy4gQSBtZWRpZGEgcXVlIGVsIHNocmlua2FnZSBzZSBpbnRlbnNpZmljYSwgdG9kb3MgbG9zIGNvZWZpY2llbnRlcyBzZSBjb250cmFlbiBwcm9ncmVzaXZhbWVudGUgaGFjaWEgY2Vyby4gTGFzIHZhcmlhYmxlcyBjdXlvcyBjb2VmaWNpZW50ZXMgY2FlbiByw6FwaWRhbWVudGUgaW5kaWNhbiBtZW5vciByZWxldmFuY2lhIGV4cGxpY2F0aXZhLCBtaWVudHJhcyBxdWUgbGFzIHF1ZSByZXNpc3RlbiBtw6FzIHRpZW1wbyBhbGVqYWRhcyBkZSBjZXJvIHNvbiBsYXMgcXVlIGVsIG1vZGVsbyBjb25zaWRlcmEgcmVsYXRpdmFtZW50ZSBtw6FzIGluZm9ybWF0aXZhcy4NCg0KDQo=